icu_datetime/pattern/
names.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
5use super::{
6    DateTimePattern, DateTimePatternFormatter, GetNameForCyclicYearError, GetNameForDayPeriodError,
7    GetNameForEraError, GetNameForMonthError, GetNameForWeekdayError, MonthPlaceholderValue,
8    PatternLoadError, UnsupportedCalendarError,
9};
10use crate::error::ErrorField;
11use crate::fieldsets::enums::{CompositeDateTimeFieldSet, CompositeFieldSet};
12use crate::provider::fields::{self, FieldLength, FieldSymbol};
13use crate::provider::neo::{marker_attrs, *};
14use crate::provider::pattern::PatternItem;
15use crate::provider::time_zones::tz;
16use crate::size_test_macro::size_test;
17use crate::FixedCalendarDateTimeFormatter;
18use crate::{external_loaders::*, DateTimeFormatterPreferences};
19use crate::{scaffold::*, DateTimeFormatter, DateTimeFormatterLoadError};
20use core::fmt;
21use core::marker::PhantomData;
22use icu_calendar::types::{EraYear, MonthCode};
23use icu_calendar::AnyCalendar;
24use icu_decimal::options::DecimalFormatterOptions;
25use icu_decimal::options::GroupingStrategy;
26use icu_decimal::provider::{DecimalDigitsV1, DecimalSymbolsV1};
27use icu_decimal::DecimalFormatter;
28use icu_provider::prelude::*;
29
30/// Choices for loading year names.
31#[derive(Debug, Copy, Clone, PartialEq, Eq)]
32#[non_exhaustive]
33pub enum YearNameLength {
34    /// An abbreviated calendar-dependent year or era name.
35    ///
36    /// Examples:
37    ///
38    /// - "AD"
39    /// - "甲子"
40    Abbreviated,
41    /// A wide calendar-dependent year or era name.
42    ///
43    /// Examples:
44    ///
45    /// - "Anno Domini"
46    /// - "甲子"
47    Wide,
48    /// A narrow calendar-dependent year or era name. Not necesarily unique.
49    ///
50    /// Examples:
51    ///
52    /// - "A"
53    /// - "甲子"
54    Narrow,
55}
56
57impl YearNameLength {
58    pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
59        use marker_attrs::Length;
60        let length = match self {
61            YearNameLength::Abbreviated => Length::Abbr,
62            YearNameLength::Wide => Length::Wide,
63            YearNameLength::Narrow => Length::Narrow,
64        };
65        marker_attrs::name_attr_for(marker_attrs::Context::Format, length)
66    }
67
68    pub(crate) fn from_field_length(field_length: FieldLength) -> Option<Self> {
69        // UTS 35 says that "G..GGG" and "U..UUU" are all Abbreviated
70        let field_length = field_length.numeric_to_abbr();
71        match field_length {
72            FieldLength::Three => Some(YearNameLength::Abbreviated),
73            FieldLength::Four => Some(YearNameLength::Wide),
74            FieldLength::Five => Some(YearNameLength::Narrow),
75            _ => None,
76        }
77    }
78
79    /// Returns an [`ErrorField`] sufficient for error reporting.
80    pub(crate) fn to_approximate_error_field(self) -> ErrorField {
81        let field_length = match self {
82            YearNameLength::Abbreviated => FieldLength::Three,
83            YearNameLength::Wide => FieldLength::Four,
84            YearNameLength::Narrow => FieldLength::Five,
85        };
86        ErrorField(fields::Field {
87            symbol: FieldSymbol::Era,
88            length: field_length,
89        })
90    }
91}
92
93/// Choices for loading month names.
94#[derive(Debug, Copy, Clone, PartialEq, Eq)]
95#[non_exhaustive]
96pub enum MonthNameLength {
97    /// An abbreviated calendar-dependent month name for formatting with other fields.
98    ///
99    /// Example: "Sep"
100    Abbreviated,
101    /// A wide calendar-dependent month name for formatting with other fields.
102    ///
103    /// Example: "September"
104    Wide,
105    /// A narrow calendar-dependent month name for formatting with other fields. Not necesarily unique.
106    ///
107    /// Example: "S"
108    Narrow,
109    /// An abbreviated calendar-dependent month name for stand-alone display.
110    ///
111    /// Example: "Sep"
112    StandaloneAbbreviated,
113    /// A wide calendar-dependent month name for stand-alone display.
114    ///
115    /// Example: "September"
116    StandaloneWide,
117    /// A narrow calendar-dependent month name for stand-alone display. Not necesarily unique.
118    ///
119    /// Example: "S"
120    StandaloneNarrow,
121}
122
123impl MonthNameLength {
124    pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
125        use marker_attrs::{Context, Length};
126        let (context, length) = match self {
127            MonthNameLength::Abbreviated => (Context::Format, Length::Abbr),
128            MonthNameLength::Wide => (Context::Format, Length::Wide),
129            MonthNameLength::Narrow => (Context::Format, Length::Narrow),
130            MonthNameLength::StandaloneAbbreviated => (Context::Standalone, Length::Abbr),
131            MonthNameLength::StandaloneWide => (Context::Standalone, Length::Wide),
132            MonthNameLength::StandaloneNarrow => (Context::Standalone, Length::Narrow),
133        };
134        marker_attrs::name_attr_for(context, length)
135    }
136
137    pub(crate) fn from_field(
138        field_symbol: fields::Month,
139        field_length: FieldLength,
140    ) -> Option<Self> {
141        use fields::Month;
142        match (field_symbol, field_length) {
143            (Month::Format, FieldLength::Three) => Some(MonthNameLength::Abbreviated),
144            (Month::Format, FieldLength::Four) => Some(MonthNameLength::Wide),
145            (Month::Format, FieldLength::Five) => Some(MonthNameLength::Narrow),
146            (Month::StandAlone, FieldLength::Three) => Some(MonthNameLength::StandaloneAbbreviated),
147            (Month::StandAlone, FieldLength::Four) => Some(MonthNameLength::StandaloneWide),
148            (Month::StandAlone, FieldLength::Five) => Some(MonthNameLength::StandaloneNarrow),
149            _ => None,
150        }
151    }
152
153    /// Returns an [`ErrorField`] sufficient for error reporting.
154    pub(crate) fn to_approximate_error_field(self) -> ErrorField {
155        use fields::Month;
156        let (field_symbol, field_length) = match self {
157            MonthNameLength::Abbreviated => (Month::Format, FieldLength::Three),
158            MonthNameLength::Wide => (Month::Format, FieldLength::Four),
159            MonthNameLength::Narrow => (Month::Format, FieldLength::Five),
160            MonthNameLength::StandaloneAbbreviated => (Month::StandAlone, FieldLength::Three),
161            MonthNameLength::StandaloneWide => (Month::StandAlone, FieldLength::Four),
162            MonthNameLength::StandaloneNarrow => (Month::StandAlone, FieldLength::Five),
163        };
164        ErrorField(fields::Field {
165            symbol: FieldSymbol::Month(field_symbol),
166            length: field_length,
167        })
168    }
169}
170
171/// Choices for loading weekday names.
172#[derive(Debug, Copy, Clone, PartialEq, Eq)]
173#[non_exhaustive]
174pub enum WeekdayNameLength {
175    /// An abbreviated weekday name for formatting with other fields.
176    ///
177    /// Example: "Tue"
178    Abbreviated,
179    /// A wide weekday name for formatting with other fields.
180    ///
181    /// Example: "Tuesday"
182    Wide,
183    /// A narrow weekday name for formatting with other fields. Not necesarily unique.
184    ///
185    /// Example: "T"
186    Narrow,
187    /// A short weekday name for formatting with other fields.
188    ///
189    /// Example: "Tu"
190    Short,
191    /// An abbreviated weekday name for stand-alone display.
192    ///
193    /// Example: "Tue"
194    StandaloneAbbreviated,
195    /// A wide weekday name for stand-alone display.
196    ///
197    /// Example: "Tuesday"
198    StandaloneWide,
199    /// A narrow weekday name for stand-alone display. Not necesarily unique.
200    ///
201    /// Example: "T"
202    StandaloneNarrow,
203    /// A short weekday name for stand-alone display.
204    ///
205    /// Example: "Tu"
206    StandaloneShort,
207}
208
209impl WeekdayNameLength {
210    pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
211        use marker_attrs::{Context, Length};
212        // UTS 35 says that "e" and "E" have the same non-numeric names
213        let (context, length) = match self {
214            WeekdayNameLength::Abbreviated => (Context::Format, Length::Abbr),
215            WeekdayNameLength::Wide => (Context::Format, Length::Wide),
216            WeekdayNameLength::Narrow => (Context::Format, Length::Narrow),
217            WeekdayNameLength::Short => (Context::Format, Length::Short),
218            WeekdayNameLength::StandaloneAbbreviated => (Context::Standalone, Length::Abbr),
219            WeekdayNameLength::StandaloneWide => (Context::Standalone, Length::Wide),
220            WeekdayNameLength::StandaloneNarrow => (Context::Standalone, Length::Narrow),
221            WeekdayNameLength::StandaloneShort => (Context::Standalone, Length::Short),
222        };
223        marker_attrs::name_attr_for(context, length)
224    }
225
226    pub(crate) fn from_field(
227        field_symbol: fields::Weekday,
228        field_length: FieldLength,
229    ) -> Option<Self> {
230        use fields::Weekday;
231        // UTS 35 says that "e" and "E" have the same non-numeric names
232        let field_symbol = field_symbol.to_format_symbol();
233        // UTS 35 says that "E..EEE" are all Abbreviated
234        // However, this doesn't apply to "e" and "c".
235        let field_length = if matches!(field_symbol, fields::Weekday::Format) {
236            field_length.numeric_to_abbr()
237        } else {
238            field_length
239        };
240        match (field_symbol, field_length) {
241            (Weekday::Format, FieldLength::Three) => Some(WeekdayNameLength::Abbreviated),
242            (Weekday::Format, FieldLength::Four) => Some(WeekdayNameLength::Wide),
243            (Weekday::Format, FieldLength::Five) => Some(WeekdayNameLength::Narrow),
244            (Weekday::Format, FieldLength::Six) => Some(WeekdayNameLength::Short),
245            (Weekday::StandAlone, FieldLength::Three) => {
246                Some(WeekdayNameLength::StandaloneAbbreviated)
247            }
248            (Weekday::StandAlone, FieldLength::Four) => Some(WeekdayNameLength::StandaloneWide),
249            (Weekday::StandAlone, FieldLength::Five) => Some(WeekdayNameLength::StandaloneNarrow),
250            (Weekday::StandAlone, FieldLength::Six) => Some(WeekdayNameLength::StandaloneShort),
251            _ => None,
252        }
253    }
254
255    /// Returns an [`ErrorField`] sufficient for error reporting.
256    pub(crate) fn to_approximate_error_field(self) -> ErrorField {
257        use fields::Weekday;
258        let (field_symbol, field_length) = match self {
259            WeekdayNameLength::Abbreviated => (Weekday::Format, FieldLength::Three),
260            WeekdayNameLength::Wide => (Weekday::Format, FieldLength::Four),
261            WeekdayNameLength::Narrow => (Weekday::Format, FieldLength::Five),
262            WeekdayNameLength::Short => (Weekday::Format, FieldLength::Six),
263            WeekdayNameLength::StandaloneAbbreviated => (Weekday::StandAlone, FieldLength::Three),
264            WeekdayNameLength::StandaloneWide => (Weekday::StandAlone, FieldLength::Four),
265            WeekdayNameLength::StandaloneNarrow => (Weekday::StandAlone, FieldLength::Five),
266            WeekdayNameLength::StandaloneShort => (Weekday::StandAlone, FieldLength::Six),
267        };
268        ErrorField(fields::Field {
269            symbol: FieldSymbol::Weekday(field_symbol),
270            length: field_length,
271        })
272    }
273}
274
275/// Choices for loading day period names.
276#[derive(Debug, Copy, Clone, PartialEq, Eq)]
277#[non_exhaustive]
278pub enum DayPeriodNameLength {
279    /// An abbreviated 12-hour day period name, including display names for 0h and 12h.
280    ///
281    /// Examples:
282    ///
283    /// - "AM"
284    /// - "mid."
285    Abbreviated,
286    /// A wide 12-hour day period name, including display names for 0h and 12h.
287    ///
288    /// The wide form may be the same as the abbreviated form if the "real" long form
289    /// (eg "ante meridiem") is not customarily used.
290    ///
291    /// Examples:
292    ///
293    /// - "AM"
294    /// - "mignight"
295    Wide,
296    /// An abbreviated 12-hour day period name, including display names for 0h and 12h.
297    ///
298    /// The narrow form must be unique, unlike some other fields.
299    ///
300    /// Examples:
301    ///
302    /// - "AM"
303    /// - "md"
304    Narrow,
305}
306
307impl DayPeriodNameLength {
308    pub(crate) fn to_attributes(self) -> &'static DataMarkerAttributes {
309        use marker_attrs::Length;
310        let length = match self {
311            DayPeriodNameLength::Abbreviated => Length::Abbr,
312            DayPeriodNameLength::Wide => Length::Wide,
313            DayPeriodNameLength::Narrow => Length::Narrow,
314        };
315        marker_attrs::name_attr_for(marker_attrs::Context::Format, length)
316    }
317
318    pub(crate) fn from_field(
319        field_symbol: fields::DayPeriod,
320        field_length: FieldLength,
321    ) -> Option<Self> {
322        use fields::DayPeriod;
323        // Names for 'a' and 'b' are stored in the same data marker
324        let field_symbol = match field_symbol {
325            DayPeriod::NoonMidnight => DayPeriod::AmPm,
326            other => other,
327        };
328        // UTS 35 says that "a..aaa" and "b..bbb" are all Abbreviated
329        let field_length = field_length.numeric_to_abbr();
330        match (field_symbol, field_length) {
331            (DayPeriod::AmPm, FieldLength::Three) => Some(DayPeriodNameLength::Abbreviated),
332            (DayPeriod::AmPm, FieldLength::Four) => Some(DayPeriodNameLength::Wide),
333            (DayPeriod::AmPm, FieldLength::Five) => Some(DayPeriodNameLength::Narrow),
334            _ => None,
335        }
336    }
337
338    /// Returns an [`ErrorField`] sufficient for error reporting.
339    pub(crate) fn to_approximate_error_field(self) -> ErrorField {
340        // Names for 'a' and 'b' are stored in the same data marker
341        let field_symbol = fields::DayPeriod::AmPm;
342        let field_length = match self {
343            DayPeriodNameLength::Abbreviated => FieldLength::Three,
344            DayPeriodNameLength::Wide => FieldLength::Four,
345            DayPeriodNameLength::Narrow => FieldLength::Five,
346        };
347        ErrorField(fields::Field {
348            symbol: FieldSymbol::DayPeriod(field_symbol),
349            length: field_length,
350        })
351    }
352}
353
354pub(crate) struct EmptyDataProvider;
355
356impl<M> DataProvider<M> for EmptyDataProvider
357where
358    M: DataMarker,
359{
360    fn load(&self, base_req: DataRequest) -> Result<DataResponse<M>, DataError> {
361        Err(DataErrorKind::MarkerNotFound.with_req(M::INFO, base_req))
362    }
363}
364
365size_test!(
366    FixedCalendarDateTimeNames<icu_calendar::Gregorian>,
367    typed_date_time_names_size,
368    328
369);
370
371/// A low-level type that formats datetime patterns with localized names.
372/// The calendar should be chosen at compile time.
373#[doc = typed_date_time_names_size!()]
374///
375/// Type parameters:
376///
377/// 1. The calendar chosen at compile time for additional type safety
378/// 2. A field set containing the fields that might be formatted
379///
380/// By default, the field set is set to [`CompositeDateTimeFieldSet`],
381/// meaning that dates and times, but not time zones, are supported. A smaller
382/// field set results in smaller stack size.
383///
384/// To support all fields including time zones, use [`CompositeFieldSet`].
385///
386/// [`CompositeFieldSet`]: crate::fieldsets::enums::CompositeFieldSet
387/// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
388///
389/// # Examples
390///
391/// ```
392/// use icu::calendar::Gregorian;
393/// use icu::datetime::input::Date;
394/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
395/// use icu::datetime::pattern::DateTimePattern;
396/// use icu::datetime::pattern::MonthNameLength;
397/// use icu::datetime::pattern::WeekdayNameLength;
398/// use icu::datetime::pattern::DayPeriodNameLength;
399/// use icu::locale::locale;
400/// use icu::datetime::input::{DateTime, Time};
401/// use writeable::assert_try_writeable_eq;
402///
403/// // Create an instance that can format abbreviated month, weekday, and day period names:
404/// let mut names: FixedCalendarDateTimeNames<Gregorian> =
405///     FixedCalendarDateTimeNames::try_new(locale!("uk").into()).unwrap();
406/// names
407///     .include_month_names(MonthNameLength::Abbreviated)
408///     .unwrap()
409///     .include_weekday_names(WeekdayNameLength::Abbreviated)
410///     .unwrap()
411///     .include_day_period_names(DayPeriodNameLength::Abbreviated)
412///     .unwrap();
413///
414/// // Create a pattern from a pattern string (note: K is the hour with h11 hour cycle):
415/// let pattern_str = "E MMM d y -- K:mm a";
416/// let pattern: DateTimePattern = pattern_str.parse().unwrap();
417///
418/// // Test it:
419/// let datetime = DateTime { date: Date::try_new_gregorian(2023, 11, 20).unwrap(), time: Time::try_new(12, 35, 3, 0).unwrap() };
420/// assert_try_writeable_eq!(names.with_pattern_unchecked(&pattern).format(&datetime), "пн лист. 20 2023 -- 0:35 пп");
421/// ```
422///
423/// If the correct data is not loaded, an error will occur:
424///
425/// ```
426/// use icu::calendar::Gregorian;
427/// use icu::datetime::input::Date;
428/// use icu::datetime::pattern::FormattedDateTimePatternError;
429/// use icu::datetime::parts;
430/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
431/// use icu::datetime::pattern::{DateTimePattern, PatternLoadError};
432/// use icu::datetime::fieldsets::enums::CompositeFieldSet;
433/// use icu::locale::locale;
434/// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
435/// use icu::datetime::input::{Time, TimeZoneInfo, ZonedDateTime};
436/// use icu_provider_adapters::empty::EmptyDataProvider;
437/// use writeable::{Part, assert_try_writeable_parts_eq};
438///
439/// // Unstable API used only for error construction below
440/// use icu::datetime::provider::fields::{Field, FieldLength, FieldSymbol, Weekday};
441///
442/// // Create an instance that can format all fields (CompositeFieldSet):
443/// let mut names: FixedCalendarDateTimeNames<Gregorian, CompositeFieldSet> =
444///     FixedCalendarDateTimeNames::try_new(locale!("en").into()).unwrap();
445///
446/// // Create a pattern from a pattern string:
447/// let pattern_str = "'It is:' E MMM d y G 'at' h:mm:ssSSS a zzzz";
448/// let pattern: DateTimePattern = pattern_str.parse().unwrap();
449///
450/// // The pattern string contains lots of symbols including "E", "MMM", and "a",
451/// // but we did not load any data!
452///
453/// let mut dtz = ZonedDateTime::try_full_from_str("2023-11-20T11:35:03+00:00[Europe/London]", Gregorian, IanaParser::new(), VariantOffsetsCalculator::new()).unwrap();
454///
455/// // Missing data is filled in on a best-effort basis, and an error is signaled.
456/// assert_try_writeable_parts_eq!(
457///     names.with_pattern_unchecked(&pattern).format(&dtz),
458///     "It is: mon M11 20 2023 ce at 11:35:03.000 AM +0000",
459///     Err(FormattedDateTimePatternError::NamesNotLoaded(Field { symbol: FieldSymbol::Weekday(Weekday::Format), length: FieldLength::One }.into())),
460///     [
461///         (7, 10, Part::ERROR), // mon
462///         (7, 10, parts::WEEKDAY), // mon
463///         (11, 14, Part::ERROR), // M11
464///         (11, 14, parts::MONTH), // M11
465///         (15, 17, icu::decimal::parts::INTEGER), // 20
466///         (15, 17, parts::DAY), // 20
467///         (18, 22, icu::decimal::parts::INTEGER), // 2023
468///         (18, 22, parts::YEAR), // 2023
469///         (23, 25, Part::ERROR), // CE
470///         (23, 25, parts::ERA), // CE
471///         (29, 31, icu::decimal::parts::INTEGER), // 11
472///         (29, 31, parts::HOUR), // 11
473///         (32, 34, icu::decimal::parts::INTEGER), // 35
474///         (32, 34, parts::MINUTE), // 35
475///         (35, 41, parts::SECOND), // 03.000
476///         (35, 37, icu::decimal::parts::INTEGER), // 03
477///         (37, 38, icu::decimal::parts::DECIMAL), // .
478///         (38, 41, icu::decimal::parts::FRACTION), // 000
479///         (42, 44, Part::ERROR), // AM
480///         (42, 44, parts::DAY_PERIOD), // AM
481///         (45, 50, Part::ERROR), // +0000
482///         (45, 50, parts::TIME_ZONE_NAME), // +0000
483///     ]
484/// );
485///
486/// // To make the error occur sooner, one can use an EmptyDataProvider:
487/// let empty = EmptyDataProvider::new();
488/// assert!(matches!(
489///     names.load_for_pattern(&empty, &pattern),
490///     Err(PatternLoadError::Data(_, _)),
491/// ));
492/// ```
493///
494/// If the pattern contains fields inconsistent with the receiver, an error will occur:
495///
496/// ```
497/// use icu::calendar::Gregorian;
498/// use icu::datetime::pattern::FormattedDateTimePatternError;
499/// use icu::datetime::parts;
500/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
501/// use icu::datetime::pattern::DateTimePattern;
502/// use icu::datetime::unchecked::MissingInputFieldKind;
503/// use icu::datetime::fieldsets::zone::LocalizedOffsetLong;
504/// use icu::locale::locale;
505/// use icu::datetime::input::{DateTime, TimeZoneInfo};
506/// use writeable::{Part, assert_try_writeable_parts_eq};
507///
508/// // Create an instance that can format abbreviated month, weekday, and day period names:
509/// let mut names: FixedCalendarDateTimeNames<Gregorian, LocalizedOffsetLong> =
510///     FixedCalendarDateTimeNames::try_new(locale!("en").into()).unwrap();
511///
512/// // Create a pattern from a pattern string:
513/// let pattern_str = "'It is:' E MMM d y G 'at' h:mm:ssSSS a zzzz";
514/// let pattern: DateTimePattern = pattern_str.parse().unwrap();
515///
516/// // The pattern string contains lots of symbols including "E", "MMM", and "a",
517/// // but the `FixedCalendarDateTimeNames` is configured to format only time zones!
518/// // Further, the time zone we provide doesn't contain any offset into!
519/// // Missing data is filled in on a best-effort basis, and an error is signaled.
520/// assert_try_writeable_parts_eq!(
521///     names.with_pattern_unchecked(&pattern).format(&TimeZoneInfo::unknown()),
522///     "It is: {E} {M} {d} {y} {G} at {h}:{m}:{s} {a} {z}",
523///     Err(FormattedDateTimePatternError::MissingInputField(MissingInputFieldKind::Weekday)),
524///     [
525///         (7, 10, Part::ERROR), // {E}
526///         (7, 10, parts::WEEKDAY), // {E}
527///         (11, 14, Part::ERROR), // {M}
528///         (11, 14, parts::MONTH), // {M}
529///         (15, 18, Part::ERROR), // {d}
530///         (15, 18, parts::DAY), // {d}
531///         (19, 22, Part::ERROR), // {y}
532///         (19, 22, parts::YEAR), // {y}
533///         (23, 26, Part::ERROR), // {G}
534///         (23, 26, parts::ERA), // {G}
535///         (30, 33, Part::ERROR), // {h}
536///         (30, 33, parts::HOUR), // {h}
537///         (34, 37, Part::ERROR), // {m}
538///         (34, 37, parts::MINUTE), // {m}
539///         (38, 41, Part::ERROR), // {s}
540///         (38, 41, parts::SECOND), // {s}
541///         (42, 45, Part::ERROR), // {a}
542///         (42, 45, parts::DAY_PERIOD), // {a}
543///         (46, 49, Part::ERROR), // {z}
544///         (46, 49, parts::TIME_ZONE_NAME), // {z}
545///     ]
546/// );
547/// ```
548///
549/// Multiple types of time zone data can be loaded into a [`FixedCalendarDateTimeNames`]:
550///
551/// ```
552/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
553/// use icu::datetime::fieldsets::enums::ZoneFieldSet;
554/// use icu::locale::locale;
555/// use icu::datetime::input::{DateTime, Time};
556/// use writeable::assert_try_writeable_eq;
557///
558/// // Create an instance that can format abbreviated month, weekday, and day period names:
559/// let mut names: FixedCalendarDateTimeNames<(), ZoneFieldSet> =
560///     FixedCalendarDateTimeNames::try_new(locale!("uk").into()).unwrap();
561///
562/// // Load the names for generic short:
563/// names.include_time_zone_essentials().unwrap();
564/// names.include_time_zone_generic_short_names().unwrap();
565/// names.include_time_zone_location_names().unwrap();
566///
567/// // The same functions can be called a second time (nothing will happen):
568/// names.include_time_zone_essentials().unwrap();
569/// names.include_time_zone_generic_short_names().unwrap();
570/// names.include_time_zone_location_names().unwrap();
571///
572/// // We can load names for a different zone style:
573/// names.include_time_zone_generic_long_names().unwrap();
574/// ```
575///
576/// However, new time zone names cannot be added into a formatter that already has them. If you
577/// need this functionality, see <https://github.com/unicode-org/icu4x/issues/6063>
578///
579/// ```
580/// use icu::datetime::fieldsets::enums::ZoneFieldSet;
581/// use icu::datetime::fieldsets::zone;
582/// use icu::datetime::pattern::FixedCalendarDateTimeNames;
583/// use icu::datetime::NoCalendarFormatter;
584/// use icu::locale::locale;
585/// use icu_datetime::pattern::PatternLoadError;
586/// use icu_provider::DataError;
587/// use icu_provider::DataErrorKind;
588///
589/// let prefs = locale!("uk").into();
590///
591/// // Create a formatter for generic long time zones:
592/// let formatter =
593///     NoCalendarFormatter::try_new(prefs, zone::GenericLong).unwrap();
594///
595/// // Convert it to a FixedCalendarDateTimeNames:
596/// let mut names =
597///     FixedCalendarDateTimeNames::from_formatter(prefs, formatter)
598///         .cast_into_fset::<ZoneFieldSet>();
599///
600/// // Specific names cannot be added:
601/// assert!(matches!(
602///     names.include_time_zone_specific_long_names(),
603///     Err(PatternLoadError::Data(
604///         DataError {
605///             kind: DataErrorKind::InconsistentData(_),
606///             ..
607///         },
608///         _
609///     ))
610/// ));
611/// ```
612#[derive(Debug, Clone)]
613pub struct FixedCalendarDateTimeNames<C, FSet: DateTimeNamesMarker = CompositeDateTimeFieldSet> {
614    prefs: DateTimeFormatterPreferences,
615    inner: RawDateTimeNames<FSet>,
616    metadata: DateTimeNamesMetadata,
617    _calendar: PhantomData<C>,
618}
619
620/// Extra metadata associated with DateTimeNames but not DateTimeFormatter.
621#[derive(Debug, Clone)]
622pub(crate) struct DateTimeNamesMetadata {
623    zone_checksum: Option<u64>,
624}
625
626impl DateTimeNamesMetadata {
627    /// No impl Default: emphasize when we create a new empty instance
628    #[inline]
629    pub(crate) fn new_empty() -> Self {
630        Self {
631            zone_checksum: None,
632        }
633    }
634    /// If mz_periods is already populated, we can't load anything else because
635    /// we can't verify the checksum. Set a blank checksum in this case.
636    #[inline]
637    pub(crate) fn new_from_previous<M: DateTimeNamesMarker>(names: &RawDateTimeNames<M>) -> Self {
638        if names.mz_periods.get().inner.get_option().is_some() {
639            Self {
640                zone_checksum: Some(0),
641            }
642        } else {
643            Self::new_empty()
644        }
645    }
646}
647
648/// A low-level type that formats datetime patterns with localized names.
649/// The calendar is chosen in the constructor at runtime.
650///
651/// Currently this only supports loading of non-calendar-specific names, but
652/// additional functions may be added in the future. If you need this, see
653/// <https://github.com/unicode-org/icu4x/issues/6107>
654#[derive(Debug, Clone)]
655pub struct DateTimeNames<FSet: DateTimeNamesMarker> {
656    inner: FixedCalendarDateTimeNames<(), FSet>,
657    calendar: FormattableAnyCalendar,
658}
659
660pub(crate) struct RawDateTimeNames<FSet: DateTimeNamesMarker> {
661    year_names: <FSet::YearNames as NamesContainer<YearNamesV1, YearNameLength>>::Container,
662    month_names: <FSet::MonthNames as NamesContainer<MonthNamesV1, MonthNameLength>>::Container,
663    weekday_names:
664        <FSet::WeekdayNames as NamesContainer<WeekdayNamesV1, WeekdayNameLength>>::Container,
665    dayperiod_names:
666        <FSet::DayPeriodNames as NamesContainer<DayPeriodNamesV1, DayPeriodNameLength>>::Container,
667    zone_essentials: <FSet::ZoneEssentials as NamesContainer<tz::EssentialsV1, ()>>::Container,
668    locations_root: <FSet::ZoneLocationsRoot as NamesContainer<tz::LocationsRootV1, ()>>::Container,
669    locations: <FSet::ZoneLocations as NamesContainer<tz::LocationsOverrideV1, ()>>::Container,
670    exemplars_root: <FSet::ZoneExemplarsRoot as NamesContainer<tz::CitiesRootV1, ()>>::Container,
671    exemplars: <FSet::ZoneExemplars as NamesContainer<tz::CitiesOverrideV1, ()>>::Container,
672    mz_generic_long: <FSet::ZoneGenericLong as NamesContainer<tz::MzGenericLongV1, ()>>::Container,
673    mz_generic_short:
674        <FSet::ZoneGenericShort as NamesContainer<tz::MzGenericShortV1, ()>>::Container,
675    mz_standard_long:
676        <FSet::ZoneStandardLong as NamesContainer<tz::MzStandardLongV1, ()>>::Container,
677    mz_specific_long:
678        <FSet::ZoneSpecificLong as NamesContainer<tz::MzSpecificLongV1, ()>>::Container,
679    mz_specific_short:
680        <FSet::ZoneSpecificShort as NamesContainer<tz::MzSpecificShortV1, ()>>::Container,
681    mz_periods: <FSet::MetazoneLookup as NamesContainer<tz::MzPeriodV1, ()>>::Container,
682    // TODO(#4340): Make the DecimalFormatter optional
683    decimal_formatter: Option<DecimalFormatter>,
684    _marker: PhantomData<FSet>,
685}
686
687// Need a custom impl because not all of the associated types impl Debug
688impl<FSet: DateTimeNamesMarker> fmt::Debug for RawDateTimeNames<FSet> {
689    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
690        f.debug_struct("RawDateTimeNames")
691            .field("year_names", &self.year_names)
692            .field("month_names", &self.month_names)
693            .field("weekday_names", &self.weekday_names)
694            .field("dayperiod_names", &self.dayperiod_names)
695            .field("zone_essentials", &self.zone_essentials)
696            .field("locations_root", &self.locations_root)
697            .field("locations", &self.locations)
698            .field("exemplars_root", &self.exemplars_root)
699            .field("exemplars", &self.exemplars)
700            .field("mz_generic_long", &self.mz_generic_long)
701            .field("mz_generic_short", &self.mz_generic_short)
702            .field("mz_standard_long", &self.mz_standard_long)
703            .field("mz_specific_long", &self.mz_specific_long)
704            .field("mz_specific_short", &self.mz_specific_short)
705            .field("mz_periods", &self.mz_periods)
706            .field("decimal_formatter", &self.decimal_formatter)
707            .finish()
708    }
709}
710
711impl<FSet: DateTimeNamesMarker> Clone for RawDateTimeNames<FSet> {
712    fn clone(&self) -> Self {
713        Self {
714            year_names: self.year_names.clone(),
715            month_names: self.month_names.clone(),
716            weekday_names: self.weekday_names.clone(),
717            dayperiod_names: self.dayperiod_names.clone(),
718            zone_essentials: self.zone_essentials.clone(),
719            locations_root: self.locations_root.clone(),
720            locations: self.locations.clone(),
721            exemplars_root: self.exemplars_root.clone(),
722            exemplars: self.exemplars.clone(),
723            mz_generic_long: self.mz_generic_long.clone(),
724            mz_generic_short: self.mz_generic_short.clone(),
725            mz_standard_long: self.mz_standard_long.clone(),
726            mz_specific_long: self.mz_specific_long.clone(),
727            mz_specific_short: self.mz_specific_short.clone(),
728            mz_periods: self.mz_periods.clone(),
729            decimal_formatter: self.decimal_formatter.clone(),
730            _marker: PhantomData,
731        }
732    }
733}
734
735impl<FSet: DateTimeNamesMarker> RawDateTimeNames<FSet> {
736    pub(crate) fn cast_into_fset<FSet2: DateTimeNamesFrom<FSet>>(self) -> RawDateTimeNames<FSet2> {
737        RawDateTimeNames {
738            year_names: FSet2::map_year_names(self.year_names),
739            month_names: FSet2::map_month_names(self.month_names),
740            weekday_names: FSet2::map_weekday_names(self.weekday_names),
741            dayperiod_names: FSet2::map_day_period_names(self.dayperiod_names),
742            zone_essentials: FSet2::map_zone_essentials(self.zone_essentials),
743            locations_root: FSet2::map_zone_locations_root(self.locations_root),
744            locations: FSet2::map_zone_locations(self.locations),
745            exemplars_root: FSet2::map_zone_exemplars_root(self.exemplars_root),
746            exemplars: FSet2::map_zone_exemplars(self.exemplars),
747            mz_generic_long: FSet2::map_zone_generic_long(self.mz_generic_long),
748            mz_generic_short: FSet2::map_zone_generic_short(self.mz_generic_short),
749            mz_standard_long: FSet2::map_zone_standard_long(self.mz_standard_long),
750            mz_specific_long: FSet2::map_zone_specific_long(self.mz_specific_long),
751            mz_specific_short: FSet2::map_zone_specific_short(self.mz_specific_short),
752            mz_periods: FSet2::map_metazone_lookup(self.mz_periods),
753            decimal_formatter: self.decimal_formatter,
754            _marker: PhantomData,
755        }
756    }
757}
758
759#[derive(Debug, Copy, Clone)]
760pub(crate) struct RawDateTimeNamesBorrowed<'l> {
761    year_names: OptionalNames<YearNameLength, &'l YearNames<'l>>,
762    month_names: OptionalNames<MonthNameLength, &'l MonthNames<'l>>,
763    weekday_names: OptionalNames<WeekdayNameLength, &'l LinearNames<'l>>,
764    dayperiod_names: OptionalNames<DayPeriodNameLength, &'l LinearNames<'l>>,
765    zone_essentials: OptionalNames<(), &'l tz::Essentials<'l>>,
766    locations_root: OptionalNames<(), &'l tz::Locations<'l>>,
767    locations: OptionalNames<(), &'l tz::Locations<'l>>,
768    exemplars_root: OptionalNames<(), &'l tz::ExemplarCities<'l>>,
769    exemplars: OptionalNames<(), &'l tz::ExemplarCities<'l>>,
770    mz_generic_long: OptionalNames<(), &'l tz::MzGeneric<'l>>,
771    mz_standard_long: OptionalNames<(), &'l tz::MzGeneric<'l>>,
772    mz_generic_short: OptionalNames<(), &'l tz::MzGeneric<'l>>,
773    mz_specific_long: OptionalNames<(), &'l tz::MzSpecific<'l>>,
774    mz_specific_short: OptionalNames<(), &'l tz::MzSpecific<'l>>,
775    mz_periods: OptionalNames<(), &'l tz::MzPeriod<'l>>,
776    pub(crate) decimal_formatter: Option<&'l DecimalFormatter>,
777}
778
779impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
780    /// Constructor that takes a selected locale and creates an empty instance.
781    ///
782    /// For an example, see [`FixedCalendarDateTimeNames`].
783    ///
784    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
785    ///
786    /// [📚 Help choosing a constructor](icu_provider::constructors)
787    #[cfg(feature = "compiled_data")]
788    pub fn try_new(prefs: DateTimeFormatterPreferences) -> Result<Self, DataError> {
789        let mut names = Self {
790            prefs,
791            inner: RawDateTimeNames::new_without_number_formatting(),
792            metadata: DateTimeNamesMetadata::new_empty(), // OK: this is a constructor
793            _calendar: PhantomData,
794        };
795        names.include_decimal_formatter()?;
796        Ok(names)
797    }
798
799    #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::try_new)]
800    pub fn try_new_unstable<P>(
801        provider: &P,
802        prefs: DateTimeFormatterPreferences,
803    ) -> Result<Self, DataError>
804    where
805        P: DataProvider<DecimalSymbolsV1> + DataProvider<DecimalDigitsV1> + ?Sized,
806    {
807        let mut names = Self {
808            prefs,
809            inner: RawDateTimeNames::new_without_number_formatting(),
810            metadata: DateTimeNamesMetadata::new_empty(), // OK: this is a constructor
811            _calendar: PhantomData,
812        };
813        names.load_decimal_formatter(provider)?;
814        Ok(names)
815    }
816
817    icu_provider::gen_buffer_data_constructors!(
818        (prefs: DateTimeFormatterPreferences) -> error: DataError,
819        functions: [
820            try_new: skip,
821            try_new_with_buffer_provider,
822            try_new_unstable,
823            Self,
824        ]
825    );
826
827    /// Creates a completely empty instance, not even with number formatting.
828    ///
829    /// # Examples
830    ///
831    /// Errors occur if a number formatter is not loaded but one is required:
832    ///
833    /// ```
834    /// use icu::calendar::Gregorian;
835    /// use icu::datetime::input::Date;
836    /// use icu::datetime::parts;
837    /// use icu::datetime::pattern::FormattedDateTimePatternError;
838    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
839    /// use icu::datetime::pattern::DateTimePattern;
840    /// use icu::datetime::fieldsets::enums::DateFieldSet;
841    /// use icu::locale::locale;
842    /// use writeable::{Part, assert_try_writeable_parts_eq};
843    ///
844    /// // Create an instance that can format only date fields:
845    /// let names: FixedCalendarDateTimeNames<Gregorian, DateFieldSet> =
846    ///     FixedCalendarDateTimeNames::new_without_number_formatting(locale!("en").into());
847    ///
848    /// // Create a pattern from a pattern string:
849    /// let pattern_str = "'It is:' y-MM-dd";
850    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
851    ///
852    /// // The pattern string contains lots of numeric symbols,
853    /// // but we did not load any data!
854    ///
855    /// let date = Date::try_new_gregorian(2024, 7, 1).unwrap();
856    ///
857    /// // Missing data is filled in on a best-effort basis, and an error is signaled.
858    /// // (note that the padding is ignored in this fallback mode)
859    /// assert_try_writeable_parts_eq!(
860    ///     names.with_pattern_unchecked(&pattern).format(&date),
861    ///     "It is: 2024-07-01",
862    ///     Err(FormattedDateTimePatternError::DecimalFormatterNotLoaded),
863    ///     [
864    ///         (7, 11, Part::ERROR), // 2024
865    ///         (7, 11, parts::YEAR), // 2024
866    ///         (12, 14, Part::ERROR), // 07
867    ///         (12, 14, parts::MONTH), // 07
868    ///         (15, 17, Part::ERROR), // 01
869    ///         (15, 17, parts::DAY), // 01
870    ///     ]
871    /// );
872    /// ```
873    pub fn new_without_number_formatting(prefs: DateTimeFormatterPreferences) -> Self {
874        Self {
875            prefs,
876            inner: RawDateTimeNames::new_without_number_formatting(),
877            metadata: DateTimeNamesMetadata::new_empty(), // OK: this is a constructor
878            _calendar: PhantomData,
879        }
880    }
881}
882
883impl<C: CldrCalendar, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
884    /// Creates an instance with the names loaded in a [`FixedCalendarDateTimeFormatter`].
885    ///
886    /// This function requires passing in the [`DateTimeFormatterPreferences`] because it is not
887    /// retained in the formatter. Pass the same value or else unexpected behavior may occur.
888    ///
889    /// # Examples
890    ///
891    /// ```
892    /// use icu::datetime::input::Date;
893    /// use icu::datetime::input::{DateTime, Time};
894    /// use icu::datetime::FixedCalendarDateTimeFormatter;
895    /// use icu::datetime::fieldsets::{YMD, YMDT};
896    /// use icu::datetime::pattern::{FixedCalendarDateTimeNames, DayPeriodNameLength};
897    /// use icu::locale::locale;
898    /// use writeable::assert_writeable_eq;
899    ///
900    /// let prefs = locale!("es-MX").into();
901    ///
902    /// let formatter =
903    ///     FixedCalendarDateTimeFormatter::try_new(
904    ///         prefs,
905    ///         YMD::long(),
906    ///     )
907    ///     .unwrap();
908    ///
909    /// assert_writeable_eq!(
910    ///     formatter.format(&Date::try_new_gregorian(2025, 2, 13).unwrap()),
911    ///     "13 de febrero de 2025"
912    /// );
913    ///
914    /// // Change the YMD formatter to a YMDT formatter, after loading day period names.
915    /// // This assumes that the locale uses Abbreviated names for the given semantic skeleton!
916    /// let mut names = FixedCalendarDateTimeNames::from_formatter(prefs, formatter).cast_into_fset::<YMDT>();
917    /// names.include_day_period_names(DayPeriodNameLength::Abbreviated).unwrap();
918    /// let formatter = names.try_into_formatter(YMD::long().with_time_hm()).unwrap();
919    ///
920    /// assert_writeable_eq!(
921    ///     formatter.format(&DateTime {
922    ///         date: Date::try_new_gregorian(2025, 2, 13).unwrap(),
923    ///         time: Time::start_of_day(),
924    ///     }),
925    ///     "13 de febrero de 2025, 12:00 a.m."
926    /// );
927    /// ```
928    pub fn from_formatter(
929        prefs: DateTimeFormatterPreferences,
930        formatter: FixedCalendarDateTimeFormatter<C, FSet>,
931    ) -> Self {
932        let metadata = DateTimeNamesMetadata::new_from_previous(&formatter.names);
933        Self {
934            prefs,
935            inner: formatter.names,
936            metadata,
937            _calendar: PhantomData,
938        }
939    }
940
941    fn from_parts(
942        prefs: DateTimeFormatterPreferences,
943        parts: (RawDateTimeNames<FSet>, DateTimeNamesMetadata),
944    ) -> Self {
945        Self {
946            prefs,
947            inner: parts.0,
948            metadata: parts.1,
949            _calendar: PhantomData,
950        }
951    }
952}
953
954impl<C: CldrCalendar, FSet: DateTimeMarkers> FixedCalendarDateTimeNames<C, FSet>
955where
956    FSet::D: TypedDateDataMarkers<C>,
957    FSet::T: TimeMarkers,
958    FSet::Z: ZoneMarkers,
959    FSet: GetField<CompositeFieldSet>,
960{
961    /// Loads a pattern for the given field set with compiled data and returns a [`FixedCalendarDateTimeFormatter`].
962    ///
963    /// The names in the current [`FixedCalendarDateTimeNames`] _must_ be sufficient for the field set.
964    /// If not, the input object will be returned with an error.
965    ///
966    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
967    ///
968    /// [📚 Help choosing a constructor](icu_provider::constructors)
969    ///
970    /// # Examples
971    ///
972    /// ```
973    /// use icu::datetime::fieldsets::T;
974    /// use icu::datetime::input::Time;
975    /// use icu::datetime::pattern::{
976    ///     DayPeriodNameLength, FixedCalendarDateTimeNames,
977    /// };
978    /// use icu::locale::locale;
979    /// use writeable::assert_writeable_eq;
980    ///
981    /// let names =
982    ///     FixedCalendarDateTimeNames::<(), _>::new_without_number_formatting(
983    ///         locale!("es-MX").into(),
984    ///     );
985    ///
986    /// let field_set = T::hm();
987    ///
988    /// // Cannot convert yet: no names are loaded
989    /// let mut names = names.try_into_formatter(field_set).unwrap_err().1;
990    ///
991    /// // Load the data we need:
992    /// names
993    ///     .include_day_period_names(DayPeriodNameLength::Abbreviated)
994    ///     .unwrap();
995    /// names.include_decimal_formatter().unwrap();
996    ///
997    /// // Now the conversion is successful:
998    /// let formatter = names.try_into_formatter(field_set).unwrap();
999    ///
1000    /// assert_writeable_eq!(formatter.format(&Time::start_of_day()), "12:00 a.m.");
1001    /// ```
1002    #[allow(clippy::result_large_err)] // returning self as the error
1003    #[cfg(feature = "compiled_data")]
1004    pub fn try_into_formatter(
1005        self,
1006        field_set: FSet,
1007    ) -> Result<FixedCalendarDateTimeFormatter<C, FSet>, (DateTimeFormatterLoadError, Self)>
1008    where
1009        crate::provider::Baked: AllFixedCalendarPatternDataMarkers<C, FSet>,
1010    {
1011        FixedCalendarDateTimeFormatter::try_new_internal_with_names(
1012            &crate::provider::Baked,
1013            &EmptyDataProvider,
1014            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1015            self.prefs,
1016            field_set.get_field(),
1017            self.inner,
1018            self.metadata,
1019        )
1020        .map_err(|e| (e.0, Self::from_parts(self.prefs, e.1)))
1021    }
1022
1023    #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::try_into_formatter)]
1024    #[allow(clippy::result_large_err)] // returning self as the error
1025    pub fn try_into_formatter_unstable<P>(
1026        self,
1027        provider: &P,
1028        field_set: FSet,
1029    ) -> Result<FixedCalendarDateTimeFormatter<C, FSet>, (DateTimeFormatterLoadError, Self)>
1030    where
1031        P: AllFixedCalendarPatternDataMarkers<C, FSet> + ?Sized,
1032    {
1033        FixedCalendarDateTimeFormatter::try_new_internal_with_names(
1034            provider,
1035            &EmptyDataProvider,
1036            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1037            self.prefs,
1038            field_set.get_field(),
1039            self.inner,
1040            self.metadata,
1041        )
1042        .map_err(|e| (e.0, Self::from_parts(self.prefs, e.1)))
1043    }
1044
1045    #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::try_into_formatter)]
1046    #[allow(clippy::result_large_err)] // returning self as the error
1047    #[cfg(feature = "serde")]
1048    pub fn try_into_formatter_with_buffer_provider<P>(
1049        self,
1050        provider: &P,
1051        field_set: FSet,
1052    ) -> Result<FixedCalendarDateTimeFormatter<C, FSet>, (DateTimeFormatterLoadError, Self)>
1053    where
1054        P: BufferProvider + ?Sized,
1055    {
1056        FixedCalendarDateTimeFormatter::try_new_internal_with_names(
1057            &provider.as_deserializing(),
1058            &EmptyDataProvider,
1059            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1060            self.prefs,
1061            field_set.get_field(),
1062            self.inner,
1063            self.metadata,
1064        )
1065        .map_err(|e| (e.0, Self::from_parts(self.prefs, e.1)))
1066    }
1067}
1068
1069impl<FSet: DateTimeNamesMarker> DateTimeNames<FSet> {
1070    /// Creates a completely empty instance, not even with number formatting,
1071    /// with the specified calendar.
1072    pub fn try_new_with_calendar_without_number_formatting(
1073        prefs: DateTimeFormatterPreferences,
1074        calendar: AnyCalendar,
1075    ) -> Result<Self, UnsupportedCalendarError> {
1076        let kind = calendar.kind();
1077        let calendar = FormattableAnyCalendar::try_from_any_calendar(calendar)
1078            .ok_or(UnsupportedCalendarError { kind })?;
1079        Ok(Self {
1080            inner: FixedCalendarDateTimeNames::new_without_number_formatting(prefs),
1081            calendar,
1082        })
1083    }
1084
1085    /// Creates an instance with the names and calendar loaded in a [`DateTimeFormatter`].
1086    ///
1087    /// This function requires passing in the [`DateTimeFormatterPreferences`] because it is not
1088    /// retained in the formatter. Pass the same value or else unexpected behavior may occur.
1089    ///
1090    /// # Examples
1091    ///
1092    /// ```
1093    /// use icu::datetime::input::Date;
1094    /// use icu::datetime::input::{DateTime, Time};
1095    /// use icu::datetime::DateTimeFormatter;
1096    /// use icu::datetime::fieldsets::{YMD, YMDT};
1097    /// use icu::datetime::pattern::{DateTimeNames, DayPeriodNameLength};
1098    /// use icu::locale::locale;
1099    /// use writeable::assert_writeable_eq;
1100    ///
1101    /// let prefs = locale!("es-MX").into();
1102    ///
1103    /// let formatter =
1104    ///     DateTimeFormatter::try_new(
1105    ///         prefs,
1106    ///         YMD::long(),
1107    ///     )
1108    ///     .unwrap();
1109    ///
1110    /// assert_writeable_eq!(
1111    ///     formatter.format(&Date::try_new_iso(2025, 2, 13).unwrap()),
1112    ///     "13 de febrero de 2025"
1113    /// );
1114    ///
1115    /// // Change the YMD formatter to a YMDT formatter, after loading day period names.
1116    /// // This assumes that the locale uses Abbreviated names for the given semantic skeleton!
1117    /// let mut names = DateTimeNames::from_formatter(prefs, formatter).cast_into_fset::<YMDT>();
1118    /// names.as_mut().include_day_period_names(DayPeriodNameLength::Abbreviated).unwrap();
1119    /// let formatter = names.try_into_formatter(YMD::long().with_time_hm()).unwrap();
1120    ///
1121    /// assert_writeable_eq!(
1122    ///     formatter.format(&DateTime {
1123    ///         date: Date::try_new_iso(2025, 2, 13).unwrap(),
1124    ///         time: Time::start_of_day(),
1125    ///     }),
1126    ///     "13 de febrero de 2025, 12:00 a.m."
1127    /// );
1128    /// ```
1129    pub fn from_formatter(
1130        prefs: DateTimeFormatterPreferences,
1131        formatter: DateTimeFormatter<FSet>,
1132    ) -> Self {
1133        let metadata = DateTimeNamesMetadata::new_from_previous(&formatter.names);
1134        Self::from_parts(
1135            prefs,
1136            (formatter.calendar.into_tagged(), formatter.names, metadata),
1137        )
1138    }
1139
1140    fn from_parts(
1141        prefs: DateTimeFormatterPreferences,
1142        parts: (
1143            FormattableAnyCalendar,
1144            RawDateTimeNames<FSet>,
1145            DateTimeNamesMetadata,
1146        ),
1147    ) -> Self {
1148        Self {
1149            inner: FixedCalendarDateTimeNames {
1150                prefs,
1151                inner: parts.1,
1152                metadata: parts.2,
1153                _calendar: PhantomData,
1154            },
1155            calendar: parts.0,
1156        }
1157    }
1158}
1159
1160impl<FSet: DateTimeMarkers> DateTimeNames<FSet>
1161where
1162    FSet::D: DateDataMarkers,
1163    FSet::T: TimeMarkers,
1164    FSet::Z: ZoneMarkers,
1165    FSet: GetField<CompositeFieldSet>,
1166{
1167    /// Loads a pattern for the given field set with compiled data and returns a [`DateTimeFormatter`].
1168    ///
1169    /// The names in the current [`DateTimeNames`] _must_ be sufficient for the field set.
1170    /// If not, the input object will be returned with an error.
1171    ///
1172    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1173    ///
1174    /// [📚 Help choosing a constructor](icu_provider::constructors)
1175    ///
1176    /// # Examples
1177    ///
1178    /// ```
1179    /// use icu::calendar::{AnyCalendar, AnyCalendarKind};
1180    /// use icu::datetime::fieldsets::T;
1181    /// use icu::datetime::input::Time;
1182    /// use icu::datetime::pattern::{DateTimeNames, DayPeriodNameLength};
1183    /// use icu::locale::locale;
1184    /// use writeable::assert_writeable_eq;
1185    ///
1186    /// let kind = AnyCalendarKind::new(locale!("es-MX").into());
1187    /// let calendar = AnyCalendar::new(kind);
1188    ///
1189    /// let names = DateTimeNames::try_new_with_calendar_without_number_formatting(
1190    ///     locale!("es-MX").into(),
1191    ///     calendar,
1192    /// )
1193    /// .expect("All locale-default calendars are supported");
1194    ///
1195    /// let field_set = T::hm();
1196    ///
1197    /// // Cannot convert yet: no names are loaded
1198    /// let mut names = names.try_into_formatter(field_set).unwrap_err().1;
1199    ///
1200    /// // Load the data we need:
1201    /// names
1202    ///     .as_mut()
1203    ///     .include_day_period_names(DayPeriodNameLength::Abbreviated)
1204    ///     .unwrap();
1205    /// names.as_mut().include_decimal_formatter().unwrap();
1206    ///
1207    /// // Now the conversion is successful:
1208    /// let formatter = names.try_into_formatter(field_set).unwrap();
1209    ///
1210    /// assert_writeable_eq!(formatter.format(&Time::start_of_day()), "12:00 a.m.");
1211    /// ```
1212    #[allow(clippy::result_large_err)] // returning self as the error
1213    #[cfg(feature = "compiled_data")]
1214    pub fn try_into_formatter(
1215        self,
1216        field_set: FSet,
1217    ) -> Result<DateTimeFormatter<FSet>, (DateTimeFormatterLoadError, Self)>
1218    where
1219        crate::provider::Baked: AllAnyCalendarPatternDataMarkers<FSet>,
1220    {
1221        DateTimeFormatter::try_new_internal_with_calendar_and_names(
1222            &crate::provider::Baked,
1223            &EmptyDataProvider,
1224            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1225            self.inner.prefs,
1226            field_set.get_field(),
1227            self.calendar,
1228            self.inner.inner,
1229            self.inner.metadata,
1230        )
1231        .map_err(|e| (e.0, Self::from_parts(self.inner.prefs, e.1)))
1232    }
1233
1234    #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::try_into_formatter)]
1235    #[allow(clippy::result_large_err)] // returning self as the error
1236    pub fn try_into_formatter_unstable<P>(
1237        self,
1238        provider: &P,
1239        field_set: FSet,
1240    ) -> Result<DateTimeFormatter<FSet>, (DateTimeFormatterLoadError, Self)>
1241    where
1242        P: AllAnyCalendarPatternDataMarkers<FSet> + ?Sized,
1243    {
1244        DateTimeFormatter::try_new_internal_with_calendar_and_names(
1245            provider,
1246            &EmptyDataProvider,
1247            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1248            self.inner.prefs,
1249            field_set.get_field(),
1250            self.calendar,
1251            self.inner.inner,
1252            self.inner.metadata,
1253        )
1254        .map_err(|e| (e.0, Self::from_parts(self.inner.prefs, e.1)))
1255    }
1256
1257    #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER, Self::try_into_formatter)]
1258    #[allow(clippy::result_large_err)] // returning self as the error
1259    #[cfg(feature = "serde")]
1260    pub fn try_into_formatter_with_buffer_provider<P>(
1261        self,
1262        provider: &P,
1263        field_set: FSet,
1264    ) -> Result<DateTimeFormatter<FSet>, (DateTimeFormatterLoadError, Self)>
1265    where
1266        P: BufferProvider + ?Sized,
1267    {
1268        DateTimeFormatter::try_new_internal_with_calendar_and_names(
1269            &provider.as_deserializing(),
1270            &EmptyDataProvider,
1271            &ExternalLoaderUnstable(&EmptyDataProvider), // for decimals only
1272            self.inner.prefs,
1273            field_set.get_field(),
1274            self.calendar,
1275            self.inner.inner,
1276            self.inner.metadata,
1277        )
1278        .map_err(|e| (e.0, Self::from_parts(self.inner.prefs, e.1)))
1279    }
1280}
1281
1282impl<FSet: DateTimeNamesMarker> AsRef<FixedCalendarDateTimeNames<(), FSet>>
1283    for DateTimeNames<FSet>
1284{
1285    fn as_ref(&self) -> &FixedCalendarDateTimeNames<(), FSet> {
1286        &self.inner
1287    }
1288}
1289
1290impl<FSet: DateTimeNamesMarker> AsMut<FixedCalendarDateTimeNames<(), FSet>>
1291    for DateTimeNames<FSet>
1292{
1293    fn as_mut(&mut self) -> &mut FixedCalendarDateTimeNames<(), FSet> {
1294        &mut self.inner
1295    }
1296}
1297
1298impl<C: CldrCalendar, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
1299    /// Loads year (era or cycle) names for the specified length.
1300    ///
1301    /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1302    pub fn load_year_names<P>(
1303        &mut self,
1304        provider: &P,
1305        length: YearNameLength,
1306    ) -> Result<&mut Self, PatternLoadError>
1307    where
1308        P: DataProvider<C::YearNamesV1> + ?Sized,
1309    {
1310        self.inner.load_year_names(
1311            &C::YearNamesV1::bind(provider),
1312            self.prefs,
1313            length,
1314            length.to_approximate_error_field(),
1315        )?;
1316        Ok(self)
1317    }
1318
1319    /// Includes year (era or cycle) names for the specified length with compiled data.
1320    ///
1321    /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1322    ///
1323    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1324    ///
1325    /// # Examples
1326    ///
1327    /// ```
1328    /// use icu::calendar::Gregorian;
1329    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1330    /// use icu::datetime::pattern::PatternLoadError;
1331    /// use icu::datetime::pattern::YearNameLength;
1332    /// use icu::locale::locale;
1333    ///
1334    /// let mut names =
1335    ///     FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1336    ///         .unwrap();
1337    ///
1338    /// // First length is successful:
1339    /// names.include_year_names(YearNameLength::Wide).unwrap();
1340    ///
1341    /// // Attempting to load the first length a second time will succeed:
1342    /// names.include_year_names(YearNameLength::Wide).unwrap();
1343    ///
1344    /// // But loading a new length fails:
1345    /// assert!(matches!(
1346    ///     names.include_year_names(YearNameLength::Abbreviated),
1347    ///     Err(PatternLoadError::ConflictingField { .. })
1348    /// ));
1349    /// ```
1350    #[cfg(feature = "compiled_data")]
1351    pub fn include_year_names(
1352        &mut self,
1353        length: YearNameLength,
1354    ) -> Result<&mut Self, PatternLoadError>
1355    where
1356        crate::provider::Baked: icu_provider::DataProvider<<C as CldrCalendar>::YearNamesV1>,
1357    {
1358        self.load_year_names(&crate::provider::Baked, length)
1359    }
1360
1361    /// Loads month names for the specified symbol and length.
1362    ///
1363    /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1364    pub fn load_month_names<P>(
1365        &mut self,
1366        provider: &P,
1367        length: MonthNameLength,
1368    ) -> Result<&mut Self, PatternLoadError>
1369    where
1370        P: DataProvider<C::MonthNamesV1> + ?Sized,
1371    {
1372        self.inner.load_month_names(
1373            &C::MonthNamesV1::bind(provider),
1374            self.prefs,
1375            length,
1376            length.to_approximate_error_field(),
1377        )?;
1378        Ok(self)
1379    }
1380
1381    /// Includes month names for the specified symbol and length with compiled data.
1382    ///
1383    /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1384    ///
1385    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1386    ///
1387    /// # Examples
1388    ///
1389    /// ```
1390    /// use icu::calendar::Gregorian;
1391    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1392    /// use icu::datetime::pattern::MonthNameLength;
1393    /// use icu::datetime::pattern::PatternLoadError;
1394    /// use icu::locale::locale;
1395    ///
1396    /// let mut names =
1397    ///     FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1398    ///         .unwrap();
1399    ///
1400    /// // First length is successful:
1401    /// names.include_month_names(MonthNameLength::Wide).unwrap();
1402    ///
1403    /// // Attempting to load the first length a second time will succeed:
1404    /// names.include_month_names(MonthNameLength::Wide).unwrap();
1405    ///
1406    /// // But loading a new symbol or length fails:
1407    /// assert!(matches!(
1408    ///     names.include_month_names(MonthNameLength::StandaloneWide),
1409    ///     Err(PatternLoadError::ConflictingField { .. })
1410    /// ));
1411    /// assert!(matches!(
1412    ///     names.include_month_names(MonthNameLength::Abbreviated),
1413    ///     Err(PatternLoadError::ConflictingField { .. })
1414    /// ));
1415    /// ```
1416    #[cfg(feature = "compiled_data")]
1417    pub fn include_month_names(
1418        &mut self,
1419        length: MonthNameLength,
1420    ) -> Result<&mut Self, PatternLoadError>
1421    where
1422        crate::provider::Baked: icu_provider::DataProvider<<C as CldrCalendar>::MonthNamesV1>,
1423    {
1424        self.load_month_names(&crate::provider::Baked, length)
1425    }
1426}
1427
1428impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
1429    /// Loads day period names for the specified length.
1430    ///
1431    /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1432    pub fn load_day_period_names<P>(
1433        &mut self,
1434        provider: &P,
1435        length: DayPeriodNameLength,
1436    ) -> Result<&mut Self, PatternLoadError>
1437    where
1438        P: DataProvider<DayPeriodNamesV1> + ?Sized,
1439    {
1440        let provider = DayPeriodNamesV1::bind(provider);
1441        self.inner.load_day_period_names(
1442            &provider,
1443            self.prefs,
1444            length,
1445            length.to_approximate_error_field(),
1446        )?;
1447        Ok(self)
1448    }
1449
1450    /// Includes day period names for the specified length with compiled data.
1451    ///
1452    /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1453    ///
1454    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1455    ///
1456    /// # Examples
1457    ///
1458    /// ```
1459    /// use icu::calendar::Gregorian;
1460    /// use icu::datetime::pattern::DayPeriodNameLength;
1461    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1462    /// use icu::datetime::pattern::PatternLoadError;
1463    /// use icu::locale::locale;
1464    ///
1465    /// let mut names =
1466    ///     FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1467    ///         .unwrap();
1468    ///
1469    /// // First length is successful:
1470    /// names
1471    ///     .include_day_period_names(DayPeriodNameLength::Wide)
1472    ///     .unwrap();
1473    ///
1474    /// // Attempting to load the first length a second time will succeed:
1475    /// names
1476    ///     .include_day_period_names(DayPeriodNameLength::Wide)
1477    ///     .unwrap();
1478    ///
1479    /// // But loading a new length fails:
1480    /// assert!(matches!(
1481    ///     names.include_day_period_names(DayPeriodNameLength::Abbreviated),
1482    ///     Err(PatternLoadError::ConflictingField { .. })
1483    /// ));
1484    /// ```
1485    #[cfg(feature = "compiled_data")]
1486    pub fn include_day_period_names(
1487        &mut self,
1488        length: DayPeriodNameLength,
1489    ) -> Result<&mut Self, PatternLoadError> {
1490        self.load_day_period_names(&crate::provider::Baked, length)
1491    }
1492
1493    /// Loads weekday names for the specified symbol and length.
1494    ///
1495    /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1496    pub fn load_weekday_names<P>(
1497        &mut self,
1498        provider: &P,
1499        length: WeekdayNameLength,
1500    ) -> Result<&mut Self, PatternLoadError>
1501    where
1502        P: DataProvider<WeekdayNamesV1> + ?Sized,
1503    {
1504        self.inner.load_weekday_names(
1505            &WeekdayNamesV1::bind(provider),
1506            self.prefs,
1507            length,
1508            length.to_approximate_error_field(),
1509        )?;
1510        Ok(self)
1511    }
1512
1513    /// Includes weekday names for the specified symbol and length with compiled data.
1514    ///
1515    /// Does not support multiple field symbols or lengths. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
1516    ///
1517    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1518    ///
1519    /// # Examples
1520    ///
1521    /// ```
1522    /// use icu::calendar::Gregorian;
1523    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1524    /// use icu::datetime::pattern::PatternLoadError;
1525    /// use icu::datetime::pattern::WeekdayNameLength;
1526    /// use icu::locale::locale;
1527    ///
1528    /// let mut names =
1529    ///     FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("und").into())
1530    ///         .unwrap();
1531    ///
1532    /// // First length is successful:
1533    /// names
1534    ///     .include_weekday_names(WeekdayNameLength::Wide)
1535    ///     .unwrap();
1536    ///
1537    /// // Attempting to load the first length a second time will succeed:
1538    /// names
1539    ///     .include_weekday_names(WeekdayNameLength::Wide)
1540    ///     .unwrap();
1541    ///
1542    /// // But loading a new symbol or length fails:
1543    /// assert!(matches!(
1544    ///     names.include_weekday_names(WeekdayNameLength::StandaloneWide),
1545    ///     Err(PatternLoadError::ConflictingField { .. })
1546    /// ));
1547    /// assert!(matches!(
1548    ///     names.include_weekday_names(WeekdayNameLength::Abbreviated),
1549    ///     Err(PatternLoadError::ConflictingField { .. })
1550    /// ));
1551    /// ```
1552    #[cfg(feature = "compiled_data")]
1553    pub fn include_weekday_names(
1554        &mut self,
1555        length: WeekdayNameLength,
1556    ) -> Result<&mut Self, PatternLoadError> {
1557        self.load_weekday_names(&crate::provider::Baked, length)
1558    }
1559
1560    /// Loads shared essential patterns for time zone formatting.
1561    pub fn load_time_zone_essentials<P>(
1562        &mut self,
1563        provider: &P,
1564    ) -> Result<&mut Self, PatternLoadError>
1565    where
1566        P: DataProvider<tz::EssentialsV1> + ?Sized,
1567    {
1568        self.inner
1569            .load_time_zone_essentials(&tz::EssentialsV1::bind(provider), self.prefs)?;
1570        Ok(self)
1571    }
1572
1573    /// Includes shared essential patterns for time zone formatting with compiled data.
1574    ///
1575    /// This data should always be loaded when performing time zone formatting.
1576    /// By itself, it allows localized offset formats.
1577    ///
1578    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1579    ///
1580    /// # Examples
1581    ///
1582    /// ```
1583    /// use icu::calendar::Gregorian;
1584    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1585    /// use icu::datetime::input::ZonedDateTime;
1586    /// use icu::datetime::pattern::DateTimePattern;
1587    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1588    /// use icu::locale::locale;
1589    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1590    /// use writeable::assert_try_writeable_eq;
1591    ///
1592    /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
1593    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
1594    ///     Gregorian,
1595    ///     IanaParser::new(),
1596    ///     VariantOffsetsCalculator::new(),
1597    /// )
1598    /// .unwrap()
1599    /// .zone;
1600    /// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
1601    ///     "2024-07-01T00:00:00+01:00[Europe/London]",
1602    ///     Gregorian,
1603    ///     IanaParser::new(),
1604    ///     VariantOffsetsCalculator::new(),
1605    /// )
1606    /// .unwrap()
1607    /// .zone;
1608    ///
1609    /// let mut names =
1610    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1611    ///         locale!("en-GB").into(),
1612    ///     )
1613    ///     .unwrap();
1614    ///
1615    /// names.include_time_zone_essentials().unwrap();
1616    ///
1617    /// // Create a pattern with symbol `OOOO`:
1618    /// let pattern_str = "'Your time zone is:' OOOO";
1619    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1620    ///
1621    /// assert_try_writeable_eq!(
1622    ///     names
1623    ///         .with_pattern_unchecked(&pattern)
1624    ///         .format(&zone_london_winter),
1625    ///     "Your time zone is: GMT+00:00",
1626    /// );
1627    /// assert_try_writeable_eq!(
1628    ///     names
1629    ///         .with_pattern_unchecked(&pattern)
1630    ///         .format(&zone_london_summer),
1631    ///     "Your time zone is: GMT+01:00",
1632    /// );
1633    ///
1634    /// // Now try `V`:
1635    /// let pattern_str = "'Your time zone is:' V";
1636    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1637    ///
1638    /// assert_try_writeable_eq!(
1639    ///     names
1640    ///         .with_pattern_unchecked(&pattern)
1641    ///         .format(&zone_london_winter),
1642    ///     "Your time zone is: gblon",
1643    /// );
1644    ///
1645    /// // Now try `Z`:
1646    /// let pattern_str = "'Your time zone is:' Z";
1647    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1648    ///
1649    /// assert_try_writeable_eq!(
1650    ///     names
1651    ///         .with_pattern_unchecked(&pattern)
1652    ///         .format(&zone_london_winter),
1653    ///     "Your time zone is: +0000",
1654    /// );
1655    ///
1656    /// // Now try `ZZZZZ`:
1657    /// let pattern_str = "'Your time zone is:' ZZZZZ";
1658    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1659    ///
1660    /// assert_try_writeable_eq!(
1661    ///     names
1662    ///         .with_pattern_unchecked(&pattern)
1663    ///         .format(&zone_london_winter),
1664    ///     "Your time zone is: Z",
1665    /// );
1666    /// assert_try_writeable_eq!(
1667    ///     names
1668    ///         .with_pattern_unchecked(&pattern)
1669    ///         .format(&zone_london_summer),
1670    ///     "Your time zone is: +01:00",
1671    /// );
1672    /// ```
1673    #[cfg(feature = "compiled_data")]
1674    pub fn include_time_zone_essentials(&mut self) -> Result<&mut Self, PatternLoadError> {
1675        self.load_time_zone_essentials(&crate::provider::Baked)
1676    }
1677
1678    /// Loads location names for time zone formatting.
1679    pub fn load_time_zone_location_names<P>(
1680        &mut self,
1681        provider: &P,
1682    ) -> Result<&mut Self, PatternLoadError>
1683    where
1684        P: DataProvider<tz::LocationsOverrideV1> + DataProvider<tz::LocationsRootV1> + ?Sized,
1685    {
1686        self.inner.load_time_zone_location_names(
1687            &tz::LocationsOverrideV1::bind(provider),
1688            &tz::LocationsRootV1::bind(provider),
1689            self.prefs,
1690        )?;
1691        Ok(self)
1692    }
1693
1694    /// Includes location names for time zone formatting with compiled data.
1695    ///
1696    /// Important: When performing manual time zone data loading, in addition to the
1697    /// specific time zone format data, also call either:
1698    ///
1699    /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1700    /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1701    ///
1702    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1703    ///
1704    /// # Examples
1705    ///
1706    /// ```
1707    /// use icu::calendar::Gregorian;
1708    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1709    /// use icu::datetime::input::ZonedDateTime;
1710    /// use icu::datetime::pattern::DateTimePattern;
1711    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1712    /// use icu::locale::locale;
1713    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1714    /// use writeable::assert_try_writeable_eq;
1715    ///
1716    /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
1717    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
1718    ///     Gregorian,
1719    ///     IanaParser::new(),
1720    ///     VariantOffsetsCalculator::new(),
1721    /// )
1722    /// .unwrap()
1723    /// .zone;
1724    ///
1725    /// let mut names =
1726    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1727    ///         locale!("en-GB").into(),
1728    ///     )
1729    ///     .unwrap();
1730    ///
1731    /// names.include_time_zone_essentials().unwrap();
1732    /// names.include_time_zone_location_names().unwrap();
1733    ///
1734    /// // Try `VVVV`:
1735    /// let pattern_str = "'Your time zone is:' VVVV";
1736    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1737    ///
1738    /// assert_try_writeable_eq!(
1739    ///     names
1740    ///         .with_pattern_unchecked(&pattern)
1741    ///         .format(&zone_london_winter),
1742    ///     "Your time zone is: UK Time",
1743    /// );
1744    /// ```
1745    #[cfg(feature = "compiled_data")]
1746    pub fn include_time_zone_location_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1747        self.load_time_zone_location_names(&crate::provider::Baked)
1748    }
1749
1750    /// Loads exemplar city names for time zone formatting.
1751    pub fn load_time_zone_exemplar_city_names<P>(
1752        &mut self,
1753        provider: &P,
1754    ) -> Result<&mut Self, PatternLoadError>
1755    where
1756        P: DataProvider<tz::CitiesOverrideV1> + DataProvider<tz::CitiesRootV1> + ?Sized,
1757    {
1758        self.inner.load_time_zone_exemplar_city_names(
1759            &tz::CitiesOverrideV1::bind(provider),
1760            &tz::CitiesRootV1::bind(provider),
1761            self.prefs,
1762        )?;
1763        Ok(self)
1764    }
1765
1766    /// Includes exemplar city names for time zone formatting with compiled data.
1767    ///
1768    /// Important: The `VVV` format requires location data in addition to exemplar
1769    /// city data. Also call either:
1770    ///
1771    /// - [`FixedCalendarDateTimeNames::include_time_zone_location_names`]
1772    /// - [`FixedCalendarDateTimeNames::load_time_zone_location_names`]
1773    ///
1774    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1775    ///
1776    /// # Examples
1777    ///
1778    /// ```
1779    /// use icu::calendar::Gregorian;
1780    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1781    /// use icu::datetime::input::ZonedDateTime;
1782    /// use icu::datetime::pattern::DateTimePattern;
1783    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1784    /// use icu::locale::locale;
1785    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1786    /// use writeable::assert_try_writeable_eq;
1787    ///
1788    /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
1789    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
1790    ///     Gregorian,
1791    ///     IanaParser::new(),
1792    ///     VariantOffsetsCalculator::new(),
1793    /// )
1794    /// .unwrap()
1795    /// .zone;
1796    ///
1797    /// let mut names =
1798    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1799    ///         locale!("en-GB").into(),
1800    ///     )
1801    ///     .unwrap();
1802    ///
1803    /// names.include_time_zone_location_names().unwrap();
1804    /// names.include_time_zone_exemplar_city_names().unwrap();
1805    ///
1806    /// // Try `VVVV`:
1807    /// let pattern_str = "'Your time zone is:' VVV";
1808    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1809    ///
1810    /// assert_try_writeable_eq!(
1811    ///     names
1812    ///         .with_pattern_unchecked(&pattern)
1813    ///         .format(&zone_london_winter),
1814    ///     "Your time zone is: London",
1815    /// );
1816    /// ```
1817    #[cfg(feature = "compiled_data")]
1818    pub fn include_time_zone_exemplar_city_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1819        self.load_time_zone_exemplar_city_names(&crate::provider::Baked)
1820    }
1821
1822    /// Loads generic non-location long time zone names.
1823    pub fn load_time_zone_generic_long_names<P>(
1824        &mut self,
1825        provider: &P,
1826    ) -> Result<&mut Self, PatternLoadError>
1827    where
1828        P: DataProvider<tz::MzGenericLongV1>
1829            + DataProvider<tz::MzStandardLongV1>
1830            + DataProvider<tz::MzPeriodV1>
1831            + ?Sized,
1832    {
1833        self.inner.load_time_zone_generic_long_names(
1834            &tz::MzGenericLongV1::bind(provider),
1835            &tz::MzStandardLongV1::bind(provider),
1836            &tz::MzPeriodV1::bind(provider),
1837            self.prefs,
1838            &mut self.metadata,
1839        )?;
1840        Ok(self)
1841    }
1842
1843    /// Includes generic non-location long time zone names with compiled data.
1844    ///
1845    /// Important: When performing manual time zone data loading, in addition to the
1846    /// specific time zone format data, also call either:
1847    ///
1848    /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1849    /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1850    ///
1851    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1852    ///
1853    /// # Examples
1854    ///
1855    /// ```
1856    /// use icu::calendar::Gregorian;
1857    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1858    /// use icu::datetime::input::ZonedDateTime;
1859    /// use icu::datetime::pattern::DateTimePattern;
1860    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1861    /// use icu::locale::locale;
1862    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1863    /// use writeable::assert_try_writeable_eq;
1864    ///
1865    /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
1866    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
1867    ///     Gregorian,
1868    ///     IanaParser::new(),
1869    ///     VariantOffsetsCalculator::new(),
1870    /// )
1871    /// .unwrap()
1872    /// .zone;
1873    /// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
1874    ///     "2024-07-01T00:00:00+01:00[Europe/London]",
1875    ///     Gregorian,
1876    ///     IanaParser::new(),
1877    ///     VariantOffsetsCalculator::new(),
1878    /// )
1879    /// .unwrap()
1880    /// .zone;
1881    ///
1882    /// let mut names =
1883    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1884    ///         locale!("en-GB").into(),
1885    ///     )
1886    ///     .unwrap();
1887    ///
1888    /// names.include_time_zone_essentials().unwrap();
1889    /// names.include_time_zone_generic_long_names().unwrap();
1890    ///
1891    /// // Create a pattern with symbol `vvvv`:
1892    /// let pattern_str = "'Your time zone is:' vvvv";
1893    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1894    ///
1895    /// assert_try_writeable_eq!(
1896    ///     names
1897    ///         .with_pattern_unchecked(&pattern)
1898    ///         .format(&zone_london_winter),
1899    ///     "Your time zone is: Greenwich Mean Time",
1900    /// );
1901    /// assert_try_writeable_eq!(
1902    ///     names
1903    ///         .with_pattern_unchecked(&pattern)
1904    ///         .format(&zone_london_summer),
1905    ///     // Note: The year-round generic name of this zone is Greenwich
1906    ///     // Mean Time, which may be confusing since the zone observes
1907    ///     // daylight savings time. See:
1908    ///     // <https://unicode-org.atlassian.net/issues/CLDR-18378>
1909    ///     "Your time zone is: Greenwich Mean Time",
1910    /// );
1911    /// ```
1912    #[cfg(feature = "compiled_data")]
1913    pub fn include_time_zone_generic_long_names(&mut self) -> Result<&mut Self, PatternLoadError> {
1914        self.load_time_zone_generic_long_names(&crate::provider::Baked)
1915    }
1916
1917    /// Loads generic non-location short time zone names.
1918    pub fn load_time_zone_generic_short_names<P>(
1919        &mut self,
1920        provider: &P,
1921    ) -> Result<&mut Self, PatternLoadError>
1922    where
1923        P: DataProvider<tz::MzGenericShortV1> + DataProvider<tz::MzPeriodV1> + ?Sized,
1924    {
1925        self.inner.load_time_zone_generic_short_names(
1926            &tz::MzGenericShortV1::bind(provider),
1927            &tz::MzPeriodV1::bind(provider),
1928            self.prefs,
1929            &mut self.metadata,
1930        )?;
1931        Ok(self)
1932    }
1933
1934    /// Includes generic non-location short time zone names with compiled data.
1935    ///
1936    /// Important: When performing manual time zone data loading, in addition to the
1937    /// specific time zone format data, also call either:
1938    ///
1939    /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
1940    /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
1941    ///
1942    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
1943    ///
1944    /// # Examples
1945    ///
1946    /// ```
1947    /// use icu::calendar::Gregorian;
1948    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
1949    /// use icu::datetime::input::ZonedDateTime;
1950    /// use icu::datetime::pattern::DateTimePattern;
1951    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
1952    /// use icu::locale::locale;
1953    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
1954    /// use writeable::assert_try_writeable_eq;
1955    ///
1956    /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
1957    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
1958    ///     Gregorian,
1959    ///     IanaParser::new(),
1960    ///     VariantOffsetsCalculator::new(),
1961    /// )
1962    /// .unwrap()
1963    /// .zone;
1964    /// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
1965    ///     "2024-07-01T00:00:00+01:00[Europe/London]",
1966    ///     Gregorian,
1967    ///     IanaParser::new(),
1968    ///     VariantOffsetsCalculator::new(),
1969    /// )
1970    /// .unwrap()
1971    /// .zone;
1972    ///
1973    /// let mut names =
1974    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
1975    ///         locale!("en-GB").into(),
1976    ///     )
1977    ///     .unwrap();
1978    ///
1979    /// names.include_time_zone_essentials().unwrap();
1980    /// names.include_time_zone_generic_short_names().unwrap();
1981    ///
1982    /// // Create a pattern with symbol `v`:
1983    /// let pattern_str = "'Your time zone is:' v";
1984    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
1985    ///
1986    /// assert_try_writeable_eq!(
1987    ///     names
1988    ///         .with_pattern_unchecked(&pattern)
1989    ///         .format(&zone_london_winter),
1990    ///     "Your time zone is: GMT",
1991    /// );
1992    /// assert_try_writeable_eq!(
1993    ///     names
1994    ///         .with_pattern_unchecked(&pattern)
1995    ///         .format(&zone_london_summer),
1996    ///     // Note: The year-round generic name of this zone is Greenwich
1997    ///     // Mean Time, which may be confusing since the zone observes
1998    ///     // daylight savings time. See:
1999    ///     // <https://unicode-org.atlassian.net/issues/CLDR-18378>
2000    ///     "Your time zone is: GMT",
2001    /// );
2002    /// ```
2003    #[cfg(feature = "compiled_data")]
2004    pub fn include_time_zone_generic_short_names(&mut self) -> Result<&mut Self, PatternLoadError> {
2005        self.load_time_zone_generic_short_names(&crate::provider::Baked)
2006    }
2007
2008    /// Loads specific non-location long time zone names.
2009    pub fn load_time_zone_specific_long_names<P>(
2010        &mut self,
2011        provider: &P,
2012    ) -> Result<&mut Self, PatternLoadError>
2013    where
2014        P: DataProvider<tz::MzSpecificLongV1>
2015            + DataProvider<tz::MzStandardLongV1>
2016            + DataProvider<tz::MzPeriodV1>
2017            + ?Sized,
2018    {
2019        self.inner.load_time_zone_specific_long_names(
2020            &tz::MzSpecificLongV1::bind(provider),
2021            &tz::MzStandardLongV1::bind(provider),
2022            &tz::MzPeriodV1::bind(provider),
2023            self.prefs,
2024            &mut self.metadata,
2025        )?;
2026        Ok(self)
2027    }
2028
2029    /// Includes specific non-location long time zone names with compiled data.
2030    ///
2031    /// Important: When performing manual time zone data loading, in addition to the
2032    /// specific time zone format data, also call either:
2033    ///
2034    /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
2035    /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
2036    ///
2037    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2038    ///
2039    /// # Examples
2040    ///
2041    /// ```
2042    /// use icu::calendar::Gregorian;
2043    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
2044    /// use icu::datetime::input::ZonedDateTime;
2045    /// use icu::datetime::pattern::DateTimePattern;
2046    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2047    /// use icu::locale::locale;
2048    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
2049    /// use writeable::assert_try_writeable_eq;
2050    ///
2051    /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
2052    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
2053    ///     Gregorian,
2054    ///     IanaParser::new(),
2055    ///     VariantOffsetsCalculator::new(),
2056    /// )
2057    /// .unwrap()
2058    /// .zone;
2059    /// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
2060    ///     "2024-07-01T00:00:00+01:00[Europe/London]",
2061    ///     Gregorian,
2062    ///     IanaParser::new(),
2063    ///     VariantOffsetsCalculator::new(),
2064    /// )
2065    /// .unwrap()
2066    /// .zone;
2067    ///
2068    /// let mut names =
2069    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
2070    ///         locale!("en-GB").into(),
2071    ///     )
2072    ///     .unwrap();
2073    ///
2074    /// names.include_time_zone_essentials().unwrap();
2075    /// names.include_time_zone_specific_long_names().unwrap();
2076    ///
2077    /// // Create a pattern with symbol `zzzz`:
2078    /// let pattern_str = "'Your time zone is:' zzzz";
2079    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2080    ///
2081    /// assert_try_writeable_eq!(
2082    ///     names
2083    ///         .with_pattern_unchecked(&pattern)
2084    ///         .format(&zone_london_winter),
2085    ///     "Your time zone is: Greenwich Mean Time",
2086    /// );
2087    /// assert_try_writeable_eq!(
2088    ///     names
2089    ///         .with_pattern_unchecked(&pattern)
2090    ///         .format(&zone_london_summer),
2091    ///     "Your time zone is: British Summer Time",
2092    /// );
2093    /// ```
2094    #[cfg(feature = "compiled_data")]
2095    pub fn include_time_zone_specific_long_names(&mut self) -> Result<&mut Self, PatternLoadError> {
2096        self.load_time_zone_specific_long_names(&crate::provider::Baked)
2097    }
2098
2099    /// Loads specific non-location short time zone names.
2100    pub fn load_time_zone_specific_short_names<P>(
2101        &mut self,
2102        provider: &P,
2103    ) -> Result<&mut Self, PatternLoadError>
2104    where
2105        P: DataProvider<tz::MzSpecificShortV1> + DataProvider<tz::MzPeriodV1> + ?Sized,
2106    {
2107        self.inner.load_time_zone_specific_short_names(
2108            &tz::MzSpecificShortV1::bind(provider),
2109            &tz::MzPeriodV1::bind(provider),
2110            self.prefs,
2111            &mut self.metadata,
2112        )?;
2113        Ok(self)
2114    }
2115
2116    /// Includes specific non-location short time zone names with compiled data.
2117    ///
2118    /// Important: When performing manual time zone data loading, in addition to the
2119    /// specific time zone format data, also call either:
2120    ///
2121    /// - [`FixedCalendarDateTimeNames::include_time_zone_essentials`]
2122    /// - [`FixedCalendarDateTimeNames::load_time_zone_essentials`]
2123    ///
2124    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2125    ///
2126    /// # Examples
2127    ///
2128    /// ```
2129    /// use icu::calendar::Gregorian;
2130    /// use icu::datetime::fieldsets::enums::ZoneFieldSet;
2131    /// use icu::datetime::input::ZonedDateTime;
2132    /// use icu::datetime::pattern::DateTimePattern;
2133    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2134    /// use icu::locale::locale;
2135    /// use icu::time::zone::{IanaParser, VariantOffsetsCalculator};
2136    /// use writeable::assert_try_writeable_eq;
2137    ///
2138    /// let mut zone_london_winter = ZonedDateTime::try_full_from_str(
2139    ///     "2024-01-01T00:00:00+00:00[Europe/London]",
2140    ///     Gregorian,
2141    ///     IanaParser::new(),
2142    ///     VariantOffsetsCalculator::new(),
2143    /// )
2144    /// .unwrap()
2145    /// .zone;
2146    /// let mut zone_london_summer = ZonedDateTime::try_full_from_str(
2147    ///     "2024-07-01T00:00:00+01:00[Europe/London]",
2148    ///     Gregorian,
2149    ///     IanaParser::new(),
2150    ///     VariantOffsetsCalculator::new(),
2151    /// )
2152    /// .unwrap()
2153    /// .zone;
2154    ///
2155    /// let mut names =
2156    ///     FixedCalendarDateTimeNames::<Gregorian, ZoneFieldSet>::try_new(
2157    ///         locale!("en-GB").into(),
2158    ///     )
2159    ///     .unwrap();
2160    ///
2161    /// names.include_time_zone_essentials().unwrap();
2162    /// names.include_time_zone_specific_short_names().unwrap();
2163    ///
2164    /// // Create a pattern with symbol `z`:
2165    /// let pattern_str = "'Your time zone is:' z";
2166    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2167    ///
2168    /// assert_try_writeable_eq!(
2169    ///     names
2170    ///         .with_pattern_unchecked(&pattern)
2171    ///         .format(&zone_london_winter),
2172    ///     "Your time zone is: GMT",
2173    /// );
2174    /// assert_try_writeable_eq!(
2175    ///     names
2176    ///         .with_pattern_unchecked(&pattern)
2177    ///         .format(&zone_london_summer),
2178    ///     "Your time zone is: BST",
2179    /// );
2180    /// ```
2181    #[cfg(feature = "compiled_data")]
2182    pub fn include_time_zone_specific_short_names(
2183        &mut self,
2184    ) -> Result<&mut Self, PatternLoadError> {
2185        self.load_time_zone_specific_short_names(&crate::provider::Baked)
2186    }
2187
2188    /// Loads generic non-location short time zone names
2189    /// and all data required for its fallback formats.
2190    ///
2191    /// See [`GenericShort`](crate::fieldsets::zone::GenericShort)
2192    pub fn load_time_zone_generic_short_names_with_fallback<P>(
2193        &mut self,
2194        provider: &P,
2195    ) -> Result<&mut Self, PatternLoadError>
2196    where
2197        P: DataProvider<DecimalSymbolsV1>
2198            + DataProvider<DecimalDigitsV1>
2199            + DataProvider<tz::EssentialsV1>
2200            + DataProvider<tz::LocationsOverrideV1>
2201            + DataProvider<tz::LocationsRootV1>
2202            + DataProvider<tz::MzGenericShortV1>
2203            + DataProvider<tz::MzPeriodV1>
2204            + ?Sized,
2205    {
2206        let error_field = self.inner.load_time_zone_field_v_except_decimals(
2207            &tz::EssentialsV1::bind(provider),
2208            &tz::LocationsOverrideV1::bind(provider),
2209            &tz::LocationsRootV1::bind(provider),
2210            &tz::MzGenericShortV1::bind(provider),
2211            &tz::MzPeriodV1::bind(provider),
2212            self.prefs,
2213            &mut self.metadata,
2214        )?;
2215        self.load_decimal_formatter(provider)
2216            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2217        Ok(self)
2218    }
2219
2220    /// Includes generic non-location short time zone names
2221    /// and all data required for its fallback formats, with compiled data.
2222    ///
2223    /// See [`GenericShort`](crate::fieldsets::zone::GenericShort)
2224    ///
2225    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2226    #[cfg(feature = "compiled_data")]
2227    pub fn include_time_zone_generic_short_names_with_fallback(
2228        &mut self,
2229    ) -> Result<&mut Self, PatternLoadError> {
2230        let error_field = self.inner.load_time_zone_field_v_except_decimals(
2231            &tz::EssentialsV1::bind(&crate::provider::Baked),
2232            &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2233            &tz::LocationsRootV1::bind(&crate::provider::Baked),
2234            &tz::MzGenericShortV1::bind(&crate::provider::Baked),
2235            &tz::MzPeriodV1::bind(&crate::provider::Baked),
2236            self.prefs,
2237            &mut self.metadata,
2238        )?;
2239        self.include_decimal_formatter()
2240            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2241        Ok(self)
2242    }
2243
2244    /// Loads generic non-location long time zone names
2245    /// and all data required for its fallback formats.
2246    ///
2247    /// See [`GenericLong`](crate::fieldsets::zone::GenericLong)
2248    pub fn load_time_zone_generic_long_names_with_fallback<P>(
2249        &mut self,
2250        provider: &P,
2251    ) -> Result<&mut Self, PatternLoadError>
2252    where
2253        P: DataProvider<DecimalSymbolsV1>
2254            + DataProvider<DecimalDigitsV1>
2255            + DataProvider<tz::EssentialsV1>
2256            + DataProvider<tz::LocationsOverrideV1>
2257            + DataProvider<tz::LocationsRootV1>
2258            + DataProvider<tz::MzGenericLongV1>
2259            + DataProvider<tz::MzStandardLongV1>
2260            + DataProvider<tz::MzPeriodV1>
2261            + ?Sized,
2262    {
2263        let error_field = self.inner.load_time_zone_field_vvvv_except_decimals(
2264            &tz::EssentialsV1::bind(provider),
2265            &tz::LocationsOverrideV1::bind(provider),
2266            &tz::LocationsRootV1::bind(provider),
2267            &tz::MzGenericLongV1::bind(provider),
2268            &tz::MzStandardLongV1::bind(provider),
2269            &tz::MzPeriodV1::bind(provider),
2270            self.prefs,
2271            &mut self.metadata,
2272        )?;
2273        self.load_decimal_formatter(provider)
2274            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2275        Ok(self)
2276    }
2277
2278    /// Includes generic non-location long time zone names
2279    /// and all data required for its fallback formats, with compiled data.
2280    ///
2281    /// See [`GenericLong`](crate::fieldsets::zone::GenericLong)
2282    ///
2283    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2284    #[cfg(feature = "compiled_data")]
2285    pub fn include_time_zone_generic_long_names_with_fallback(
2286        &mut self,
2287    ) -> Result<&mut Self, PatternLoadError> {
2288        let error_field = self.inner.load_time_zone_field_vvvv_except_decimals(
2289            &tz::EssentialsV1::bind(&crate::provider::Baked),
2290            &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2291            &tz::LocationsRootV1::bind(&crate::provider::Baked),
2292            &tz::MzGenericLongV1::bind(&crate::provider::Baked),
2293            &tz::MzStandardLongV1::bind(&crate::provider::Baked),
2294            &tz::MzPeriodV1::bind(&crate::provider::Baked),
2295            self.prefs,
2296            &mut self.metadata,
2297        )?;
2298        self.include_decimal_formatter()
2299            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2300        Ok(self)
2301    }
2302
2303    /// Loads specific non-location short time zone names
2304    /// and all data required for its fallback formats
2305    /// except for decimal formatting.
2306    ///
2307    /// See [`SpecificShort`](crate::fieldsets::zone::SpecificShort)
2308    pub fn load_time_zone_specific_short_names_with_fallback<P>(
2309        &mut self,
2310        provider: &P,
2311    ) -> Result<&mut Self, PatternLoadError>
2312    where
2313        P: DataProvider<DecimalSymbolsV1>
2314            + DataProvider<DecimalDigitsV1>
2315            + DataProvider<tz::EssentialsV1>
2316            + DataProvider<tz::LocationsOverrideV1>
2317            + DataProvider<tz::LocationsRootV1>
2318            + DataProvider<tz::MzSpecificShortV1>
2319            + DataProvider<tz::MzPeriodV1>
2320            + ?Sized,
2321    {
2322        let error_field = self.inner.load_time_zone_field_z_except_decimals(
2323            &tz::EssentialsV1::bind(provider),
2324            &tz::MzSpecificShortV1::bind(provider),
2325            &tz::MzPeriodV1::bind(provider),
2326            self.prefs,
2327            &mut self.metadata,
2328        )?;
2329        self.load_decimal_formatter(provider)
2330            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2331        Ok(self)
2332    }
2333
2334    /// Includes specific non-location short time zone names
2335    /// and all data required for its fallback formats
2336    /// except for decimal formatting, with compiled data.
2337    ///
2338    /// See [`SpecificShort`](crate::fieldsets::zone::SpecificShort)
2339    ///
2340    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2341    #[cfg(feature = "compiled_data")]
2342    pub fn include_time_zone_specific_short_names_with_fallback(
2343        &mut self,
2344    ) -> Result<&mut Self, PatternLoadError> {
2345        let error_field = self.inner.load_time_zone_field_z_except_decimals(
2346            &tz::EssentialsV1::bind(&crate::provider::Baked),
2347            &tz::MzSpecificShortV1::bind(&crate::provider::Baked),
2348            &tz::MzPeriodV1::bind(&crate::provider::Baked),
2349            self.prefs,
2350            &mut self.metadata,
2351        )?;
2352        self.include_decimal_formatter()
2353            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2354        Ok(self)
2355    }
2356
2357    /// Loads specific non-location long time zone names
2358    /// and all data required for its fallback formats
2359    /// except for decimal formatting.
2360    ///
2361    /// See [`SpecificLong`](crate::fieldsets::zone::SpecificLong)
2362    pub fn load_time_zone_specific_long_names_with_fallback<P>(
2363        &mut self,
2364        provider: &P,
2365    ) -> Result<&mut Self, PatternLoadError>
2366    where
2367        P: DataProvider<DecimalSymbolsV1>
2368            + DataProvider<DecimalDigitsV1>
2369            + DataProvider<tz::EssentialsV1>
2370            + DataProvider<tz::LocationsOverrideV1>
2371            + DataProvider<tz::LocationsRootV1>
2372            + DataProvider<tz::MzSpecificLongV1>
2373            + DataProvider<tz::MzStandardLongV1>
2374            + DataProvider<tz::MzPeriodV1>
2375            + ?Sized,
2376    {
2377        let error_field = self.inner.load_time_zone_field_zzzz_except_decimals(
2378            &tz::EssentialsV1::bind(provider),
2379            &tz::LocationsOverrideV1::bind(provider),
2380            &tz::LocationsRootV1::bind(provider),
2381            &tz::MzStandardLongV1::bind(provider),
2382            &tz::MzSpecificLongV1::bind(provider),
2383            &tz::MzPeriodV1::bind(provider),
2384            self.prefs,
2385            &mut self.metadata,
2386        )?;
2387        self.load_decimal_formatter(provider)
2388            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2389        Ok(self)
2390    }
2391
2392    /// Includes specific non-location long time zone names
2393    /// and all data required for its fallback formats
2394    /// except for decimal formatting, with compiled data.
2395    ///
2396    /// See [`SpecificLong`](crate::fieldsets::zone::SpecificLong)
2397    ///
2398    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2399    #[cfg(feature = "compiled_data")]
2400    pub fn include_time_zone_specific_long_names_with_fallback(
2401        &mut self,
2402    ) -> Result<&mut Self, PatternLoadError> {
2403        let error_field = self.inner.load_time_zone_field_zzzz_except_decimals(
2404            &tz::EssentialsV1::bind(&crate::provider::Baked),
2405            &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2406            &tz::LocationsRootV1::bind(&crate::provider::Baked),
2407            &tz::MzStandardLongV1::bind(&crate::provider::Baked),
2408            &tz::MzSpecificLongV1::bind(&crate::provider::Baked),
2409            &tz::MzPeriodV1::bind(&crate::provider::Baked),
2410            self.prefs,
2411            &mut self.metadata,
2412        )?;
2413        self.include_decimal_formatter()
2414            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2415        Ok(self)
2416    }
2417
2418    /// Loads all data for short and long localized offset time zone formatting
2419    /// except for decimal formatting.
2420    ///
2421    /// See:
2422    ///
2423    /// - [`LocalizedOffsetShort`](crate::fieldsets::zone::LocalizedOffsetShort)
2424    /// - [`LocalizedOffsetLong`](crate::fieldsets::zone::LocalizedOffsetLong)
2425    pub fn load_time_zone_localized_offset_names_with_fallback<P>(
2426        &mut self,
2427        provider: &P,
2428    ) -> Result<&mut Self, PatternLoadError>
2429    where
2430        P: DataProvider<DecimalSymbolsV1>
2431            + DataProvider<DecimalDigitsV1>
2432            + DataProvider<tz::EssentialsV1>
2433            + ?Sized,
2434    {
2435        let error_field = self.inner.load_time_zone_field_O_except_decimals(
2436            &tz::EssentialsV1::bind(provider),
2437            self.prefs,
2438        )?;
2439        self.load_decimal_formatter(provider)
2440            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2441        Ok(self)
2442    }
2443
2444    /// Includes all data for short and long localized offset time zone formatting
2445    /// except for decimal formatting, with compiled data.
2446    ///
2447    /// See:
2448    ///
2449    /// - [`LocalizedOffsetShort`](crate::fieldsets::zone::LocalizedOffsetShort)
2450    /// - [`LocalizedOffsetLong`](crate::fieldsets::zone::LocalizedOffsetLong)
2451    ///
2452    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2453    #[cfg(feature = "compiled_data")]
2454    pub fn include_time_zone_localized_offset_names_with_fallback(
2455        &mut self,
2456    ) -> Result<&mut Self, PatternLoadError> {
2457        let error_field = self.inner.load_time_zone_field_O_except_decimals(
2458            &tz::EssentialsV1::bind(&crate::provider::Baked),
2459            self.prefs,
2460        )?;
2461        self.include_decimal_formatter()
2462            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2463        Ok(self)
2464    }
2465
2466    /// Loads a [`DecimalFormatter`] from a data provider.
2467    #[inline]
2468    pub fn load_decimal_formatter<P>(&mut self, provider: &P) -> Result<&mut Self, DataError>
2469    where
2470        P: DataProvider<DecimalSymbolsV1> + DataProvider<DecimalDigitsV1> + ?Sized,
2471    {
2472        self.inner
2473            .load_decimal_formatter(&ExternalLoaderUnstable(provider), self.prefs)?;
2474        Ok(self)
2475    }
2476
2477    /// Loads a [`DecimalFormatter`] with compiled data.
2478    ///
2479    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2480    ///
2481    /// # Examples
2482    ///
2483    /// ```
2484    /// use icu::datetime::fieldsets::enums::TimeFieldSet;
2485    /// use icu::datetime::input::Time;
2486    /// use icu::datetime::pattern::DateTimePattern;
2487    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2488    /// use icu::locale::locale;
2489    /// use writeable::assert_try_writeable_eq;
2490    ///
2491    /// let mut names = FixedCalendarDateTimeNames::<(), TimeFieldSet>::try_new(
2492    ///     locale!("bn").into(),
2493    /// )
2494    /// .unwrap();
2495    /// names.include_decimal_formatter();
2496    ///
2497    /// // Create a pattern for the time, which is all numbers
2498    /// let pattern_str = "'The current 24-hour time is:' HH:mm";
2499    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2500    ///
2501    /// let time = Time::try_new(6, 40, 33, 0).unwrap();
2502    ///
2503    /// assert_try_writeable_eq!(
2504    ///     names.with_pattern_unchecked(&pattern).format(&time),
2505    ///     "The current 24-hour time is: ০৬:৪০",
2506    /// );
2507    /// ```
2508    #[cfg(feature = "compiled_data")]
2509    #[inline]
2510    pub fn include_decimal_formatter(&mut self) -> Result<&mut Self, DataError> {
2511        self.inner
2512            .load_decimal_formatter(&ExternalLoaderCompiledData, self.prefs)?;
2513        Ok(self)
2514    }
2515}
2516
2517impl<C: CldrCalendar, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
2518    /// Associates this [`FixedCalendarDateTimeNames`] with a pattern
2519    /// without checking that all necessary data is loaded.
2520    ///
2521    /// Use this function if you know at compile time what fields your pattern contains.
2522    #[inline]
2523    pub fn with_pattern_unchecked<'l>(
2524        &'l self,
2525        pattern: &'l DateTimePattern,
2526    ) -> DateTimePatternFormatter<'l, C, FSet> {
2527        DateTimePatternFormatter::new(pattern.as_borrowed(), self.inner.as_borrowed())
2528    }
2529
2530    /// Associates this [`FixedCalendarDateTimeNames`] with a datetime pattern
2531    /// and loads all data required for that pattern.
2532    ///
2533    /// Does not duplicate textual field symbols. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
2534    pub fn load_for_pattern<'l, P>(
2535        &'l mut self,
2536        provider: &P,
2537        pattern: &'l DateTimePattern,
2538    ) -> Result<DateTimePatternFormatter<'l, C, FSet>, PatternLoadError>
2539    where
2540        P: DataProvider<C::YearNamesV1>
2541            + DataProvider<C::MonthNamesV1>
2542            + DataProvider<WeekdayNamesV1>
2543            + DataProvider<DayPeriodNamesV1>
2544            + DataProvider<tz::EssentialsV1>
2545            + DataProvider<tz::LocationsOverrideV1>
2546            + DataProvider<tz::LocationsRootV1>
2547            + DataProvider<tz::CitiesOverrideV1>
2548            + DataProvider<tz::CitiesRootV1>
2549            + DataProvider<tz::MzGenericLongV1>
2550            + DataProvider<tz::MzGenericShortV1>
2551            + DataProvider<tz::MzStandardLongV1>
2552            + DataProvider<tz::MzSpecificLongV1>
2553            + DataProvider<tz::MzSpecificShortV1>
2554            + DataProvider<tz::MzPeriodV1>
2555            + DataProvider<DecimalSymbolsV1>
2556            + DataProvider<DecimalDigitsV1>
2557            + ?Sized,
2558    {
2559        let locale = self.prefs;
2560        self.inner.load_for_pattern(
2561            &C::YearNamesV1::bind(provider),
2562            &C::MonthNamesV1::bind(provider),
2563            &WeekdayNamesV1::bind(provider),
2564            &DayPeriodNamesV1::bind(provider),
2565            &tz::EssentialsV1::bind(provider),
2566            &tz::LocationsRootV1::bind(provider),
2567            &tz::LocationsOverrideV1::bind(provider),
2568            &tz::CitiesRootV1::bind(provider),
2569            &tz::CitiesOverrideV1::bind(provider),
2570            &tz::MzGenericLongV1::bind(provider),
2571            &tz::MzGenericShortV1::bind(provider),
2572            &tz::MzStandardLongV1::bind(provider),
2573            &tz::MzSpecificLongV1::bind(provider),
2574            &tz::MzSpecificShortV1::bind(provider),
2575            &tz::MzPeriodV1::bind(provider),
2576            &ExternalLoaderUnstable(provider),
2577            locale,
2578            pattern.iter_items(),
2579            &mut self.metadata,
2580        )?;
2581        Ok(DateTimePatternFormatter::new(
2582            pattern.as_borrowed(),
2583            self.inner.as_borrowed(),
2584        ))
2585    }
2586
2587    /// Associates this [`FixedCalendarDateTimeNames`] with a pattern
2588    /// and includes all data required for that pattern, from compiled data.
2589    ///
2590    /// Does not support duplicate textual field symbols. See [#4337](https://github.com/unicode-org/icu4x/issues/4337)
2591    ///
2592    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
2593    ///
2594    /// # Examples
2595    ///
2596    /// ```
2597    /// use icu::calendar::Gregorian;
2598    /// use icu::datetime::input::Date;
2599    /// use icu::datetime::input::{DateTime, Time};
2600    /// use icu::datetime::pattern::DateTimePattern;
2601    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2602    /// use icu::locale::locale;
2603    /// use writeable::assert_try_writeable_eq;
2604    ///
2605    /// let mut names =
2606    ///     FixedCalendarDateTimeNames::<Gregorian>::try_new(locale!("en").into())
2607    ///         .unwrap();
2608    ///
2609    /// // Create a pattern from a pattern string:
2610    /// let pattern_str = "MMM d (EEEE) 'of year' y G 'at' h:mm a";
2611    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2612    ///
2613    /// // Load data for the pattern and format:
2614    /// let datetime = DateTime {
2615    ///     date: Date::try_new_gregorian(2023, 12, 5).unwrap(),
2616    ///     time: Time::try_new(17, 43, 12, 0).unwrap(),
2617    /// };
2618    /// assert_try_writeable_eq!(
2619    ///     names
2620    ///         .include_for_pattern(&pattern)
2621    ///         .unwrap()
2622    ///         .format(&datetime),
2623    ///     "Dec 5 (Tuesday) of year 2023 AD at 5:43 PM"
2624    /// );
2625    /// ```
2626    #[cfg(feature = "compiled_data")]
2627    pub fn include_for_pattern<'l>(
2628        &'l mut self,
2629        pattern: &'l DateTimePattern,
2630    ) -> Result<DateTimePatternFormatter<'l, C, FSet>, PatternLoadError>
2631    where
2632        crate::provider::Baked: DataProvider<C::YearNamesV1> + DataProvider<C::MonthNamesV1>,
2633        crate::provider::Baked: DataProvider<C::YearNamesV1> + DataProvider<C::MonthNamesV1>,
2634    {
2635        let locale = self.prefs;
2636        self.inner.load_for_pattern(
2637            &C::YearNamesV1::bind(&crate::provider::Baked),
2638            &C::MonthNamesV1::bind(&crate::provider::Baked),
2639            &WeekdayNamesV1::bind(&crate::provider::Baked),
2640            &DayPeriodNamesV1::bind(&crate::provider::Baked),
2641            &tz::EssentialsV1::bind(&crate::provider::Baked),
2642            &tz::LocationsOverrideV1::bind(&crate::provider::Baked),
2643            &tz::LocationsRootV1::bind(&crate::provider::Baked),
2644            &tz::CitiesOverrideV1::bind(&crate::provider::Baked),
2645            &tz::CitiesRootV1::bind(&crate::provider::Baked),
2646            &tz::MzGenericLongV1::bind(&crate::provider::Baked),
2647            &tz::MzGenericShortV1::bind(&crate::provider::Baked),
2648            &tz::MzStandardLongV1::bind(&crate::provider::Baked),
2649            &tz::MzSpecificLongV1::bind(&crate::provider::Baked),
2650            &tz::MzSpecificShortV1::bind(&crate::provider::Baked),
2651            &tz::MzPeriodV1::bind(&crate::provider::Baked),
2652            &ExternalLoaderCompiledData,
2653            locale,
2654            pattern.iter_items(),
2655            &mut self.metadata,
2656        )?;
2657        Ok(DateTimePatternFormatter::new(
2658            pattern.as_borrowed(),
2659            self.inner.as_borrowed(),
2660        ))
2661    }
2662}
2663
2664impl<C, FSet: DateTimeNamesMarker> FixedCalendarDateTimeNames<C, FSet> {
2665    /// Maps a [`FixedCalendarDateTimeNames`] of a specific `FSet` to a more general `FSet`.
2666    ///
2667    /// For example, this can transform a formatter for [`DateFieldSet`] to one for
2668    /// [`CompositeDateTimeFieldSet`].
2669    ///
2670    /// [`DateFieldSet`]: crate::fieldsets::enums::DateFieldSet
2671    /// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
2672    ///
2673    /// # Examples
2674    ///
2675    /// ```
2676    /// use icu::calendar::Gregorian;
2677    /// use icu::datetime::fieldsets::enums::{
2678    ///     CompositeDateTimeFieldSet, DateFieldSet,
2679    /// };
2680    /// use icu::datetime::input::Date;
2681    /// use icu::datetime::input::{DateTime, Time};
2682    /// use icu::datetime::pattern::DateTimePattern;
2683    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2684    /// use icu::datetime::pattern::MonthNameLength;
2685    /// use icu::locale::locale;
2686    /// use writeable::assert_try_writeable_eq;
2687    ///
2688    /// // Create an instance that can format abbreviated month names:
2689    /// let mut names: FixedCalendarDateTimeNames<Gregorian, DateFieldSet> =
2690    ///     FixedCalendarDateTimeNames::try_new(locale!("uk").into()).unwrap();
2691    /// names
2692    ///     .include_month_names(MonthNameLength::Abbreviated)
2693    ///     .unwrap();
2694    ///
2695    /// // Test it with a pattern:
2696    /// let pattern_str = "MMM d y";
2697    /// let pattern: DateTimePattern = pattern_str.parse().unwrap();
2698    /// let datetime = DateTime {
2699    ///     date: Date::try_new_gregorian(2023, 11, 20).unwrap(),
2700    ///     time: Time::start_of_day(),
2701    /// };
2702    /// assert_try_writeable_eq!(
2703    ///     names.with_pattern_unchecked(&pattern).format(&datetime),
2704    ///     "лист. 20 2023"
2705    /// );
2706    ///
2707    /// // Convert the field set to `CompositeDateTimeFieldSet`:
2708    /// let composite_names = names.cast_into_fset::<CompositeDateTimeFieldSet>();
2709    ///
2710    /// // It should still work:
2711    /// assert_try_writeable_eq!(
2712    ///     composite_names
2713    ///         .with_pattern_unchecked(&pattern)
2714    ///         .format(&datetime),
2715    ///     "лист. 20 2023"
2716    /// );
2717    /// ```
2718    ///
2719    /// Converting into a narrower type is not supported:
2720    ///
2721    /// ```compile_fail,E0277
2722    /// use icu::calendar::Gregorian;
2723    /// use icu::datetime::pattern::FixedCalendarDateTimeNames;
2724    /// use icu::datetime::fieldsets::enums::{DateFieldSet, CompositeDateTimeFieldSet};
2725    ///
2726    /// let composite_names: FixedCalendarDateTimeNames<Gregorian, CompositeDateTimeFieldSet> = todo!();
2727    ///
2728    /// // error[E0277]: the trait bound `(): From<DataPayloadWithVariables<DayPeriodNamesV1, FieldLength>>` is not satisfied
2729    /// let narrow_names = composite_names.cast_into_fset::<DateFieldSet>();
2730    /// ```
2731    pub fn cast_into_fset<FSet2: DateTimeNamesFrom<FSet>>(
2732        self,
2733    ) -> FixedCalendarDateTimeNames<C, FSet2> {
2734        FixedCalendarDateTimeNames {
2735            prefs: self.prefs,
2736            inner: self.inner.cast_into_fset(),
2737            metadata: self.metadata,
2738            _calendar: PhantomData,
2739        }
2740    }
2741}
2742
2743impl<FSet: DateTimeNamesMarker> DateTimeNames<FSet> {
2744    /// Maps a [`FixedCalendarDateTimeNames`] of a specific `FSet` to a more general `FSet`.
2745    ///
2746    /// For example, this can transform a formatter for [`DateFieldSet`] to one for
2747    /// [`CompositeDateTimeFieldSet`].
2748    ///
2749    /// [`DateFieldSet`]: crate::fieldsets::enums::DateFieldSet
2750    /// [`CompositeDateTimeFieldSet`]: crate::fieldsets::enums::CompositeDateTimeFieldSet
2751    pub fn cast_into_fset<FSet2: DateTimeNamesFrom<FSet>>(self) -> DateTimeNames<FSet2> {
2752        DateTimeNames {
2753            inner: self.inner.cast_into_fset(),
2754            calendar: self.calendar,
2755        }
2756    }
2757}
2758
2759impl<FSet: DateTimeNamesMarker> RawDateTimeNames<FSet> {
2760    pub(crate) fn new_without_number_formatting() -> Self {
2761        Self {
2762            year_names: <FSet::YearNames as NamesContainer<
2763                YearNamesV1,
2764                YearNameLength,
2765            >>::Container::new_empty(),
2766            month_names: <FSet::MonthNames as NamesContainer<
2767                MonthNamesV1,
2768                MonthNameLength,
2769            >>::Container::new_empty(),
2770            weekday_names: <FSet::WeekdayNames as NamesContainer<
2771                WeekdayNamesV1,
2772                WeekdayNameLength,
2773            >>::Container::new_empty(),
2774            dayperiod_names: <FSet::DayPeriodNames as NamesContainer<
2775                DayPeriodNamesV1,
2776                DayPeriodNameLength,
2777            >>::Container::new_empty(),
2778            zone_essentials: <FSet::ZoneEssentials as NamesContainer<
2779                tz::EssentialsV1,
2780                (),
2781            >>::Container::new_empty(),
2782            locations_root: <FSet::ZoneLocationsRoot as NamesContainer<
2783                tz::LocationsRootV1,
2784                (),
2785            >>::Container::new_empty(),
2786            locations: <FSet::ZoneLocations as NamesContainer<
2787                tz::LocationsOverrideV1,
2788                (),
2789            >>::Container::new_empty(),
2790            exemplars: <FSet::ZoneExemplars as NamesContainer<
2791                tz::CitiesOverrideV1,
2792                (),
2793            >>::Container::new_empty(),
2794            exemplars_root: <FSet::ZoneExemplarsRoot as NamesContainer<
2795                tz::CitiesRootV1,
2796                (),
2797            >>::Container::new_empty(),
2798            mz_generic_long: <FSet::ZoneGenericLong as NamesContainer<
2799                tz::MzGenericLongV1,
2800                (),
2801            >>::Container::new_empty(),
2802            mz_generic_short: <FSet::ZoneGenericShort as NamesContainer<
2803                tz::MzGenericShortV1,
2804                (),
2805            >>::Container::new_empty(),
2806            mz_standard_long: <FSet::ZoneStandardLong as NamesContainer<
2807                tz::MzStandardLongV1,
2808                (),
2809            >>::Container::new_empty(),
2810            mz_specific_long: <FSet::ZoneSpecificLong as NamesContainer<
2811                tz::MzSpecificLongV1,
2812                (),
2813            >>::Container::new_empty(),
2814            mz_specific_short: <FSet::ZoneSpecificShort as NamesContainer<
2815                tz::MzSpecificShortV1,
2816                (),
2817            >>::Container::new_empty(),
2818            mz_periods: <FSet::MetazoneLookup as NamesContainer<
2819                tz::MzPeriodV1,
2820                (),
2821            >>::Container::new_empty(),
2822            decimal_formatter: None,
2823            _marker: PhantomData,
2824        }
2825    }
2826
2827    pub(crate) fn as_borrowed(&self) -> RawDateTimeNamesBorrowed {
2828        RawDateTimeNamesBorrowed {
2829            year_names: self.year_names.get().inner,
2830            month_names: self.month_names.get().inner,
2831            weekday_names: self.weekday_names.get().inner,
2832            dayperiod_names: self.dayperiod_names.get().inner,
2833            zone_essentials: self.zone_essentials.get().inner,
2834            locations_root: self.locations_root.get().inner,
2835            locations: self.locations.get().inner,
2836            exemplars_root: self.exemplars_root.get().inner,
2837            exemplars: self.exemplars.get().inner,
2838            mz_generic_long: self.mz_generic_long.get().inner,
2839            mz_generic_short: self.mz_generic_short.get().inner,
2840            mz_standard_long: self.mz_standard_long.get().inner,
2841            mz_specific_long: self.mz_specific_long.get().inner,
2842            mz_specific_short: self.mz_specific_short.get().inner,
2843            mz_periods: self.mz_periods.get().inner,
2844            decimal_formatter: self.decimal_formatter.as_ref(),
2845        }
2846    }
2847
2848    pub(crate) fn load_year_names<P>(
2849        &mut self,
2850        provider: &P,
2851        prefs: DateTimeFormatterPreferences,
2852        length: YearNameLength,
2853        error_field: ErrorField,
2854    ) -> Result<(), PatternLoadError>
2855    where
2856        P: BoundDataProvider<YearNamesV1> + ?Sized,
2857    {
2858        let attributes = length.to_attributes();
2859        let locale = provider
2860            .bound_marker()
2861            .make_locale(prefs.locale_preferences);
2862        let req = DataRequest {
2863            id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2864            ..Default::default()
2865        };
2866        self.year_names
2867            .load_put(provider, req, length)
2868            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2869            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2870        Ok(())
2871    }
2872
2873    pub(crate) fn load_month_names<P>(
2874        &mut self,
2875        provider: &P,
2876        prefs: DateTimeFormatterPreferences,
2877        length: MonthNameLength,
2878        error_field: ErrorField,
2879    ) -> Result<(), PatternLoadError>
2880    where
2881        P: BoundDataProvider<MonthNamesV1> + ?Sized,
2882    {
2883        let attributes = length.to_attributes();
2884        let locale = provider
2885            .bound_marker()
2886            .make_locale(prefs.locale_preferences);
2887        let req = DataRequest {
2888            id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2889            ..Default::default()
2890        };
2891        self.month_names
2892            .load_put(provider, req, length)
2893            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2894            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2895        Ok(())
2896    }
2897
2898    pub(crate) fn load_day_period_names<P>(
2899        &mut self,
2900        provider: &P,
2901        prefs: DateTimeFormatterPreferences,
2902        length: DayPeriodNameLength,
2903        error_field: ErrorField,
2904    ) -> Result<(), PatternLoadError>
2905    where
2906        P: BoundDataProvider<DayPeriodNamesV1> + ?Sized,
2907    {
2908        let attributes = length.to_attributes();
2909        let locale = provider
2910            .bound_marker()
2911            .make_locale(prefs.locale_preferences);
2912        let req = DataRequest {
2913            id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2914            ..Default::default()
2915        };
2916        self.dayperiod_names
2917            .load_put(provider, req, length)
2918            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2919            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2920        Ok(())
2921    }
2922
2923    pub(crate) fn load_weekday_names<P>(
2924        &mut self,
2925        provider: &P,
2926        prefs: DateTimeFormatterPreferences,
2927        length: WeekdayNameLength,
2928        error_field: ErrorField,
2929    ) -> Result<(), PatternLoadError>
2930    where
2931        P: BoundDataProvider<WeekdayNamesV1> + ?Sized,
2932    {
2933        let attributes = length.to_attributes();
2934        let locale = provider
2935            .bound_marker()
2936            .make_locale(prefs.locale_preferences);
2937        let req = DataRequest {
2938            id: DataIdentifierBorrowed::for_marker_attributes_and_locale(attributes, &locale),
2939            ..Default::default()
2940        };
2941        self.weekday_names
2942            .load_put(provider, req, length)
2943            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2944            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2945        Ok(())
2946    }
2947
2948    pub(crate) fn load_time_zone_essentials<P>(
2949        &mut self,
2950        provider: &P,
2951        prefs: DateTimeFormatterPreferences,
2952    ) -> Result<ErrorField, PatternLoadError>
2953    where
2954        P: BoundDataProvider<tz::EssentialsV1> + ?Sized,
2955    {
2956        let locale = provider
2957            .bound_marker()
2958            .make_locale(prefs.locale_preferences);
2959        let error_field = ErrorField(fields::Field {
2960            symbol: FieldSymbol::TimeZone(fields::TimeZone::LocalizedOffset),
2961            length: FieldLength::Four,
2962        });
2963        let variables = ();
2964        let req = DataRequest {
2965            id: DataIdentifierBorrowed::for_locale(&locale),
2966            ..Default::default()
2967        };
2968        self.zone_essentials
2969            .load_put(provider, req, variables)
2970            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
2971            .map_err(|e| PatternLoadError::Data(e, error_field))?;
2972        Ok(error_field)
2973    }
2974
2975    pub(crate) fn load_time_zone_location_names<P, P2>(
2976        &mut self,
2977        provider: &P,
2978        root_provider: &P2,
2979        prefs: DateTimeFormatterPreferences,
2980    ) -> Result<ErrorField, PatternLoadError>
2981    where
2982        P: BoundDataProvider<tz::LocationsOverrideV1> + ?Sized,
2983        P2: BoundDataProvider<tz::LocationsRootV1> + ?Sized,
2984    {
2985        let locale = provider
2986            .bound_marker()
2987            .make_locale(prefs.locale_preferences);
2988        let error_field = ErrorField(fields::Field {
2989            symbol: FieldSymbol::TimeZone(fields::TimeZone::Location),
2990            length: FieldLength::Four,
2991        });
2992        let variables = ();
2993        let req = DataRequest {
2994            id: DataIdentifierBorrowed::for_locale(&locale),
2995            ..Default::default()
2996        };
2997        self.locations_root
2998            .load_put(root_provider, req, variables)
2999            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3000            .map_err(|e| PatternLoadError::Data(e, error_field))?;
3001        self.locations
3002            .load_put(provider, req, variables)
3003            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3004            .map_err(|e| PatternLoadError::Data(e, error_field))?;
3005        Ok(error_field)
3006    }
3007
3008    pub(crate) fn load_time_zone_exemplar_city_names<P, P2>(
3009        &mut self,
3010        provider: &P,
3011        root_provider: &P2,
3012        prefs: DateTimeFormatterPreferences,
3013    ) -> Result<ErrorField, PatternLoadError>
3014    where
3015        P: BoundDataProvider<tz::CitiesOverrideV1> + ?Sized,
3016        P2: BoundDataProvider<tz::CitiesRootV1> + ?Sized,
3017    {
3018        let locale = provider
3019            .bound_marker()
3020            .make_locale(prefs.locale_preferences);
3021        let error_field = ErrorField(fields::Field {
3022            symbol: FieldSymbol::TimeZone(fields::TimeZone::Location),
3023            length: FieldLength::Three,
3024        });
3025        let variables = ();
3026        let req = DataRequest {
3027            id: DataIdentifierBorrowed::for_locale(&locale),
3028            ..Default::default()
3029        };
3030        self.exemplars_root
3031            .load_put(root_provider, req, variables)
3032            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3033            .map_err(|e| PatternLoadError::Data(e, error_field))?;
3034        self.exemplars
3035            .load_put(provider, req, variables)
3036            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3037            .map_err(|e| PatternLoadError::Data(e, error_field))?;
3038        Ok(error_field)
3039    }
3040
3041    pub(crate) fn load_time_zone_generic_long_names(
3042        &mut self,
3043        mz_generic_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
3044        mz_standard_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3045        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3046        prefs: DateTimeFormatterPreferences,
3047        names_metadata: &mut DateTimeNamesMetadata,
3048    ) -> Result<ErrorField, PatternLoadError> {
3049        let locale = mz_generic_provider
3050            .bound_marker()
3051            .make_locale(prefs.locale_preferences);
3052        let error_field = ErrorField(fields::Field {
3053            symbol: FieldSymbol::TimeZone(fields::TimeZone::GenericNonLocation),
3054            length: FieldLength::Four,
3055        });
3056        let variables = ();
3057        let req = DataRequest {
3058            id: DataIdentifierBorrowed::for_locale(&locale),
3059            ..Default::default()
3060        };
3061        let mut save_checksum = |cs: &u64| {
3062            // get_or_insert saves the value only if the Option is None.
3063            names_metadata.zone_checksum.get_or_insert(*cs);
3064        };
3065        let cs1 = self
3066            .mz_generic_long
3067            .load_put(mz_generic_provider, req, variables)
3068            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3069            .map_err(|e| PatternLoadError::Data(e, error_field))?
3070            .checksum
3071            .inspect(&mut save_checksum);
3072        let cs2 = self
3073            .mz_standard_long
3074            .load_put(mz_standard_provider, req, variables)
3075            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3076            .map_err(|e| PatternLoadError::Data(e, error_field))?
3077            .checksum
3078            .inspect(&mut save_checksum);
3079        let cs3 = self
3080            .mz_periods
3081            .load_put(mz_period_provider, Default::default(), ())
3082            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3083            .map_err(|e| PatternLoadError::Data(e, error_field))?
3084            .checksum
3085            .inspect(&mut save_checksum);
3086        // Error if any two of the checksum Options are Some and not equal.
3087        let cs = names_metadata.zone_checksum;
3088        if cs1.or(cs) != cs || cs2.or(cs) != cs || cs3.or(cs) != cs {
3089            return Err(PatternLoadError::Data(
3090                DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3091                    .with_req(tz::MzGenericLongV1::INFO, req),
3092                error_field,
3093            ));
3094        }
3095        Ok(error_field)
3096    }
3097
3098    pub(crate) fn load_time_zone_generic_short_names(
3099        &mut self,
3100        provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
3101        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3102        prefs: DateTimeFormatterPreferences,
3103        names_metadata: &mut DateTimeNamesMetadata,
3104    ) -> Result<ErrorField, PatternLoadError> {
3105        let locale = provider
3106            .bound_marker()
3107            .make_locale(prefs.locale_preferences);
3108        let error_field = ErrorField(fields::Field {
3109            symbol: FieldSymbol::TimeZone(fields::TimeZone::GenericNonLocation),
3110            length: FieldLength::One,
3111        });
3112        let variables = ();
3113        let req = DataRequest {
3114            id: DataIdentifierBorrowed::for_locale(&locale),
3115            ..Default::default()
3116        };
3117        let mut save_checksum = |cs: &u64| {
3118            // get_or_insert saves the value only if the Option is None.
3119            names_metadata.zone_checksum.get_or_insert(*cs);
3120        };
3121        let cs1 = self
3122            .mz_generic_short
3123            .load_put(provider, req, variables)
3124            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3125            .map_err(|e| PatternLoadError::Data(e, error_field))?
3126            .checksum
3127            .inspect(&mut save_checksum);
3128        let cs2 = self
3129            .mz_periods
3130            .load_put(mz_period_provider, Default::default(), ())
3131            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3132            .map_err(|e| PatternLoadError::Data(e, error_field))?
3133            .checksum
3134            .inspect(&mut save_checksum);
3135        // Error if any two of the checksum Options are Some and not equal.
3136        let cs = names_metadata.zone_checksum;
3137        if cs1.or(cs) != cs || cs2.or(cs) != cs {
3138            return Err(PatternLoadError::Data(
3139                DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3140                    .with_req(tz::MzGenericLongV1::INFO, req),
3141                error_field,
3142            ));
3143        }
3144        Ok(error_field)
3145    }
3146
3147    pub(crate) fn load_time_zone_specific_long_names(
3148        &mut self,
3149        mz_specific_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
3150        mz_standard_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3151        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3152        prefs: DateTimeFormatterPreferences,
3153        names_metadata: &mut DateTimeNamesMetadata,
3154    ) -> Result<ErrorField, PatternLoadError> {
3155        let locale = mz_specific_provider
3156            .bound_marker()
3157            .make_locale(prefs.locale_preferences);
3158        let error_field = ErrorField(fields::Field {
3159            symbol: FieldSymbol::TimeZone(fields::TimeZone::SpecificNonLocation),
3160            length: FieldLength::Four,
3161        });
3162        let variables = ();
3163        let req = DataRequest {
3164            id: DataIdentifierBorrowed::for_locale(&locale),
3165            ..Default::default()
3166        };
3167        let mut save_checksum = |cs: &u64| {
3168            // get_or_insert saves the value only if the Option is None.
3169            names_metadata.zone_checksum.get_or_insert(*cs);
3170        };
3171        let cs1 = self
3172            .mz_specific_long
3173            .load_put(mz_specific_provider, req, variables)
3174            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3175            .map_err(|e| PatternLoadError::Data(e, error_field))?
3176            .checksum
3177            .inspect(&mut save_checksum);
3178        let cs2 = self
3179            .mz_standard_long
3180            .load_put(mz_standard_provider, req, variables)
3181            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3182            .map_err(|e| PatternLoadError::Data(e, error_field))?
3183            .checksum
3184            .inspect(&mut save_checksum);
3185        let cs3 = self
3186            .mz_periods
3187            .load_put(mz_period_provider, Default::default(), ())
3188            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3189            .map_err(|e| PatternLoadError::Data(e, error_field))?
3190            .checksum
3191            .inspect(&mut save_checksum);
3192        // Error if any two of the checksum Options are Some and not equal.
3193        let cs = names_metadata.zone_checksum;
3194        if cs1.or(cs) != cs || cs2.or(cs) != cs || cs3.or(cs) != cs {
3195            return Err(PatternLoadError::Data(
3196                DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3197                    .with_req(tz::MzSpecificLongV1::INFO, req),
3198                error_field,
3199            ));
3200        }
3201        Ok(error_field)
3202    }
3203
3204    pub(crate) fn load_time_zone_specific_short_names(
3205        &mut self,
3206        provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3207        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3208        prefs: DateTimeFormatterPreferences,
3209        names_metadata: &mut DateTimeNamesMetadata,
3210    ) -> Result<ErrorField, PatternLoadError> {
3211        let locale = provider
3212            .bound_marker()
3213            .make_locale(prefs.locale_preferences);
3214        let error_field = ErrorField(fields::Field {
3215            symbol: FieldSymbol::TimeZone(fields::TimeZone::SpecificNonLocation),
3216            length: FieldLength::One,
3217        });
3218        let variables = ();
3219        let req = DataRequest {
3220            id: DataIdentifierBorrowed::for_locale(&locale),
3221            ..Default::default()
3222        };
3223        let mut save_checksum = |cs: &u64| {
3224            // get_or_insert saves the value only if the Option is None.
3225            names_metadata.zone_checksum.get_or_insert(*cs);
3226        };
3227        let cs1 = self
3228            .mz_specific_short
3229            .load_put(provider, req, variables)
3230            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3231            .map_err(|e| PatternLoadError::Data(e, error_field))?
3232            .checksum
3233            .inspect(&mut save_checksum);
3234        let cs2 = self
3235            .mz_periods
3236            .load_put(mz_period_provider, Default::default(), ())
3237            .map_err(|e| MaybePayloadError::into_load_error(e, error_field))?
3238            .map_err(|e| PatternLoadError::Data(e, error_field))?
3239            .checksum
3240            .inspect(&mut save_checksum);
3241        // Error if any two of the checksum Options are Some and not equal.
3242        let cs = names_metadata.zone_checksum;
3243        if cs1.or(cs) != cs || cs2.or(cs) != cs {
3244            return Err(PatternLoadError::Data(
3245                DataErrorKind::InconsistentData(tz::MzPeriodV1::INFO)
3246                    .with_req(tz::MzSpecificShortV1::INFO, req),
3247                error_field,
3248            ));
3249        }
3250        Ok(error_field)
3251    }
3252
3253    pub(crate) fn load_time_zone_field_z_except_decimals(
3254        &mut self,
3255        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3256        mz_specific_short_provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3257        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3258        prefs: DateTimeFormatterPreferences,
3259        names_metadata: &mut DateTimeNamesMetadata,
3260    ) -> Result<ErrorField, PatternLoadError> {
3261        self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3262        self.load_time_zone_specific_short_names(
3263            mz_specific_short_provider,
3264            mz_period_provider,
3265            prefs,
3266            names_metadata,
3267        )
3268    }
3269
3270    #[allow(clippy::too_many_arguments)]
3271    pub(crate) fn load_time_zone_field_zzzz_except_decimals(
3272        &mut self,
3273        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3274        locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3275        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3276        mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3277        mz_specific_long_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
3278        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3279        prefs: DateTimeFormatterPreferences,
3280        names_metadata: &mut DateTimeNamesMetadata,
3281    ) -> Result<ErrorField, PatternLoadError> {
3282        self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3283        self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3284        self.load_time_zone_specific_long_names(
3285            mz_specific_long_provider,
3286            mz_standard_long_provider,
3287            mz_period_provider,
3288            prefs,
3289            names_metadata,
3290        )
3291    }
3292
3293    #[allow(clippy::too_many_arguments)] // internal function with lots of generics
3294    pub(crate) fn load_time_zone_field_v_except_decimals(
3295        &mut self,
3296        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3297        locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3298        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3299        mz_generic_short_provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
3300        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3301        prefs: DateTimeFormatterPreferences,
3302        names_metadata: &mut DateTimeNamesMetadata,
3303    ) -> Result<ErrorField, PatternLoadError> {
3304        self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3305        // For fallback:
3306        self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3307        self.load_time_zone_generic_short_names(
3308            mz_generic_short_provider,
3309            mz_period_provider,
3310            prefs,
3311            names_metadata,
3312        )
3313    }
3314
3315    #[allow(clippy::too_many_arguments)]
3316    pub(crate) fn load_time_zone_field_vvvv_except_decimals(
3317        &mut self,
3318        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3319        locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3320        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3321        mz_generic_long_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
3322        mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3323        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3324        prefs: DateTimeFormatterPreferences,
3325        names_metadata: &mut DateTimeNamesMetadata,
3326    ) -> Result<ErrorField, PatternLoadError> {
3327        self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3328        // For fallback:
3329        self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3330        self.load_time_zone_generic_long_names(
3331            mz_generic_long_provider,
3332            mz_standard_long_provider,
3333            mz_period_provider,
3334            prefs,
3335            names_metadata,
3336        )
3337    }
3338
3339    #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3340    pub(crate) fn load_time_zone_field_V(
3341        &mut self,
3342        _prefs: DateTimeFormatterPreferences,
3343    ) -> Result<(), PatternLoadError> {
3344        // no data required
3345        Ok(())
3346    }
3347
3348    #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3349    pub(crate) fn load_time_zone_field_VVV(
3350        &mut self,
3351        locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3352        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3353        exemplar_cities_provider: &(impl BoundDataProvider<tz::CitiesOverrideV1> + ?Sized),
3354        exemplar_cities_root_provider: &(impl BoundDataProvider<tz::CitiesRootV1> + ?Sized),
3355        prefs: DateTimeFormatterPreferences,
3356    ) -> Result<ErrorField, PatternLoadError> {
3357        self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)?;
3358        self.load_time_zone_exemplar_city_names(
3359            exemplar_cities_provider,
3360            exemplar_cities_root_provider,
3361            prefs,
3362        )
3363    }
3364
3365    #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3366    pub(crate) fn load_time_zone_field_VVVV_except_decimals(
3367        &mut self,
3368        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3369        locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3370        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3371        prefs: DateTimeFormatterPreferences,
3372    ) -> Result<ErrorField, PatternLoadError> {
3373        self.load_time_zone_essentials(zone_essentials_provider, prefs)?;
3374        self.load_time_zone_location_names(locations_provider, locations_root_provider, prefs)
3375    }
3376
3377    #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3378    pub(crate) fn load_time_zone_field_O_except_decimals(
3379        &mut self,
3380        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3381        prefs: DateTimeFormatterPreferences,
3382    ) -> Result<ErrorField, PatternLoadError> {
3383        self.load_time_zone_essentials(zone_essentials_provider, prefs)
3384    }
3385
3386    #[allow(non_snake_case)] // this is a private function named after the case-sensitive CLDR field
3387    pub(crate) fn load_time_zone_field_X(
3388        &mut self,
3389        _prefs: DateTimeFormatterPreferences,
3390    ) -> Result<(), PatternLoadError> {
3391        // no data required
3392        Ok(())
3393    }
3394
3395    pub(crate) fn load_decimal_formatter(
3396        &mut self,
3397        loader: &impl DecimalFormatterLoader,
3398        prefs: DateTimeFormatterPreferences,
3399    ) -> Result<(), DataError> {
3400        if self.decimal_formatter.is_some() {
3401            return Ok(());
3402        }
3403        let mut options = DecimalFormatterOptions::default();
3404        options.grouping_strategy = Some(GroupingStrategy::Never);
3405        self.decimal_formatter = Some(DecimalFormatterLoader::load(
3406            loader,
3407            (&prefs).into(),
3408            options,
3409        )?);
3410        Ok(())
3411    }
3412
3413    /// Loads all data required for formatting the given [`PatternItem`]s.
3414    ///
3415    /// This function has a lot of arguments because many of the arguments are generic,
3416    /// and pulling them out to an options struct would be cumbersome.
3417    #[allow(clippy::too_many_arguments)]
3418    pub(crate) fn load_for_pattern(
3419        &mut self,
3420        year_provider: &(impl BoundDataProvider<YearNamesV1> + ?Sized),
3421        month_provider: &(impl BoundDataProvider<MonthNamesV1> + ?Sized),
3422        weekday_provider: &(impl BoundDataProvider<WeekdayNamesV1> + ?Sized),
3423        dayperiod_provider: &(impl BoundDataProvider<DayPeriodNamesV1> + ?Sized),
3424        zone_essentials_provider: &(impl BoundDataProvider<tz::EssentialsV1> + ?Sized),
3425        locations_provider: &(impl BoundDataProvider<tz::LocationsOverrideV1> + ?Sized),
3426        locations_root_provider: &(impl BoundDataProvider<tz::LocationsRootV1> + ?Sized),
3427        exemplar_cities_provider: &(impl BoundDataProvider<tz::CitiesOverrideV1> + ?Sized),
3428        exemplar_cities_root_provider: &(impl BoundDataProvider<tz::CitiesRootV1> + ?Sized),
3429        mz_generic_long_provider: &(impl BoundDataProvider<tz::MzGenericLongV1> + ?Sized),
3430        mz_generic_short_provider: &(impl BoundDataProvider<tz::MzGenericShortV1> + ?Sized),
3431        mz_standard_long_provider: &(impl BoundDataProvider<tz::MzStandardLongV1> + ?Sized),
3432        mz_specific_long_provider: &(impl BoundDataProvider<tz::MzSpecificLongV1> + ?Sized),
3433        mz_specific_short_provider: &(impl BoundDataProvider<tz::MzSpecificShortV1> + ?Sized),
3434        mz_period_provider: &(impl BoundDataProvider<tz::MzPeriodV1> + ?Sized),
3435        decimal_formatter_loader: &impl DecimalFormatterLoader,
3436        prefs: DateTimeFormatterPreferences,
3437        pattern_items: impl Iterator<Item = PatternItem>,
3438        names_metadata: &mut DateTimeNamesMetadata,
3439    ) -> Result<(), PatternLoadError> {
3440        let mut numeric_field = None;
3441
3442        for item in pattern_items {
3443            let PatternItem::Field(field) = item else {
3444                continue;
3445            };
3446            let error_field = ErrorField(field);
3447
3448            use crate::provider::fields::*;
3449            use FieldLength::*;
3450            use FieldSymbol as FS;
3451
3452            match (field.symbol, field.length) {
3453                ///// Textual symbols /////
3454
3455                // G..GGGGG
3456                (FS::Era, One | Two | Three | Four | Five) => {
3457                    self.load_year_names(
3458                        year_provider,
3459                        prefs,
3460                        YearNameLength::from_field_length(field.length)
3461                            .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3462                        error_field,
3463                    )?;
3464                }
3465
3466                // U..UUUUU
3467                (FS::Year(Year::Cyclic), One | Two | Three | Four | Five) => {
3468                    numeric_field = Some(field);
3469                    self.load_year_names(
3470                        year_provider,
3471                        prefs,
3472                        YearNameLength::from_field_length(field.length)
3473                            .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3474                        error_field,
3475                    )?;
3476                }
3477
3478                // MMM..MMMMM, LLL..LLLLL
3479                (
3480                    FS::Month(field_symbol @ Month::Format | field_symbol @ Month::StandAlone),
3481                    Three | Four | Five,
3482                ) => {
3483                    self.load_month_names(
3484                        month_provider,
3485                        prefs,
3486                        MonthNameLength::from_field(field_symbol, field.length)
3487                            .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3488                        error_field,
3489                    )?;
3490                }
3491
3492                // e..ee, c..cc
3493                (FS::Weekday(Weekday::Local | Weekday::StandAlone), One | Two) => {
3494                    // TODO(#5643): Requires locale-aware day-of-week calculation
3495                    return Err(PatternLoadError::UnsupportedLength(ErrorField(field)));
3496                }
3497
3498                // E..EEEEEE, eee..eeeeee, ccc..cccccc
3499                (FS::Weekday(field_symbol), One | Two | Three | Four | Five | Six) => {
3500                    self.load_weekday_names(
3501                        weekday_provider,
3502                        prefs,
3503                        WeekdayNameLength::from_field(field_symbol, field.length)
3504                            .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3505                        error_field,
3506                    )?;
3507                }
3508
3509                // a..aaaaa, b..bbbbb
3510                (FS::DayPeriod(field_symbol), One | Two | Three | Four | Five) => {
3511                    self.load_day_period_names(
3512                        dayperiod_provider,
3513                        prefs,
3514                        DayPeriodNameLength::from_field(field_symbol, field.length)
3515                            .ok_or(PatternLoadError::UnsupportedLength(error_field))?,
3516                        error_field,
3517                    )?;
3518                }
3519
3520                ///// Time zone symbols /////
3521
3522                // z..zzz
3523                (FS::TimeZone(TimeZone::SpecificNonLocation), One | Two | Three) => {
3524                    self.load_time_zone_field_z_except_decimals(
3525                        zone_essentials_provider,
3526                        mz_specific_short_provider,
3527                        mz_period_provider,
3528                        prefs,
3529                        names_metadata,
3530                    )?;
3531                    numeric_field = Some(field);
3532                }
3533                // zzzz
3534                (FS::TimeZone(TimeZone::SpecificNonLocation), Four) => {
3535                    self.load_time_zone_field_zzzz_except_decimals(
3536                        zone_essentials_provider,
3537                        locations_provider,
3538                        locations_root_provider,
3539                        mz_standard_long_provider,
3540                        mz_specific_long_provider,
3541                        mz_period_provider,
3542                        prefs,
3543                        names_metadata,
3544                    )?;
3545                    numeric_field = Some(field);
3546                }
3547                // v
3548                (FS::TimeZone(TimeZone::GenericNonLocation), One) => {
3549                    self.load_time_zone_field_v_except_decimals(
3550                        zone_essentials_provider,
3551                        locations_provider,
3552                        locations_root_provider,
3553                        mz_generic_short_provider,
3554                        mz_period_provider,
3555                        prefs,
3556                        names_metadata,
3557                    )?;
3558                    numeric_field = Some(field);
3559                }
3560                // vvvv
3561                (FS::TimeZone(TimeZone::GenericNonLocation), Four) => {
3562                    self.load_time_zone_field_vvvv_except_decimals(
3563                        zone_essentials_provider,
3564                        locations_provider,
3565                        locations_root_provider,
3566                        mz_generic_long_provider,
3567                        mz_standard_long_provider,
3568                        mz_period_provider,
3569                        prefs,
3570                        names_metadata,
3571                    )?;
3572                    numeric_field = Some(field);
3573                }
3574
3575                // V
3576                (FS::TimeZone(TimeZone::Location), One) => {
3577                    self.load_time_zone_field_V(prefs)?;
3578                }
3579                // VVV
3580                (FS::TimeZone(TimeZone::Location), Three) => {
3581                    self.load_time_zone_field_VVV(
3582                        locations_provider,
3583                        locations_root_provider,
3584                        exemplar_cities_provider,
3585                        exemplar_cities_root_provider,
3586                        prefs,
3587                    )?;
3588                }
3589                // VVVV
3590                (FS::TimeZone(TimeZone::Location), Four) => {
3591                    self.load_time_zone_field_VVVV_except_decimals(
3592                        zone_essentials_provider,
3593                        locations_provider,
3594                        locations_root_provider,
3595                        prefs,
3596                    )?;
3597                    numeric_field = Some(field);
3598                }
3599                // O, OOOO
3600                (FS::TimeZone(TimeZone::LocalizedOffset), One | Four) => {
3601                    self.load_time_zone_field_O_except_decimals(zone_essentials_provider, prefs)?;
3602                    numeric_field = Some(field);
3603                }
3604                // X..XXXXX, x..xxxxx
3605                (
3606                    FS::TimeZone(TimeZone::IsoWithZ | TimeZone::Iso),
3607                    One | Two | Three | Four | Five,
3608                ) => {
3609                    self.load_time_zone_field_X(prefs)?;
3610                }
3611
3612                ///// Numeric symbols /////
3613
3614                // y+
3615                (FS::Year(Year::Calendar), _) => numeric_field = Some(field),
3616                // r+
3617                (FS::Year(Year::RelatedIso), _) => {
3618                    // always formats as ASCII
3619                }
3620
3621                // M..MM, L..LL
3622                (FS::Month(_), One | Two) => numeric_field = Some(field),
3623
3624                // d..dd
3625                (FS::Day(Day::DayOfMonth), One | Two) => numeric_field = Some(field),
3626                // D..DDD
3627                (FS::Day(Day::DayOfYear), One | Two | Three) => numeric_field = Some(field),
3628                // F
3629                (FS::Day(Day::DayOfWeekInMonth), One) => numeric_field = Some(field),
3630
3631                // K..KK, h..hh, H..HH, k..kk
3632                (FS::Hour(_), One | Two) => numeric_field = Some(field),
3633
3634                // m..mm
3635                (FS::Minute, One | Two) => numeric_field = Some(field),
3636
3637                // s..ss
3638                (FS::Second(Second::Second), One | Two) => numeric_field = Some(field),
3639
3640                // A+
3641                (FS::Second(Second::MillisInDay), _) => numeric_field = Some(field),
3642
3643                // s.S+, ss.S+ (s is modelled by length, S+ by symbol)
3644                (FS::DecimalSecond(_), One | Two) => numeric_field = Some(field),
3645
3646                ///// Unsupported symbols /////
3647                _ => {
3648                    return Err(PatternLoadError::UnsupportedLength(ErrorField(field)));
3649                }
3650            }
3651        }
3652
3653        if let Some(field) = numeric_field {
3654            self.load_decimal_formatter(decimal_formatter_loader, prefs)
3655                .map_err(|e| PatternLoadError::Data(e, ErrorField(field)))?;
3656        }
3657
3658        Ok(())
3659    }
3660}
3661
3662impl RawDateTimeNamesBorrowed<'_> {
3663    pub(crate) fn get_name_for_month(
3664        &self,
3665        field_symbol: fields::Month,
3666        field_length: FieldLength,
3667        code: MonthCode,
3668    ) -> Result<MonthPlaceholderValue, GetNameForMonthError> {
3669        let month_name_length = MonthNameLength::from_field(field_symbol, field_length)
3670            .ok_or(GetNameForMonthError::InvalidFieldLength)?;
3671        let month_names = self
3672            .month_names
3673            .get_with_variables(month_name_length)
3674            .ok_or(GetNameForMonthError::NotLoaded)?;
3675        let Some((month_number, is_leap)) = code.parsed() else {
3676            return Err(GetNameForMonthError::InvalidMonthCode);
3677        };
3678        let Some(month_index) = month_number.checked_sub(1) else {
3679            return Err(GetNameForMonthError::InvalidMonthCode);
3680        };
3681        let month_index = usize::from(month_index);
3682        let name = match month_names {
3683            MonthNames::Linear(linear) => {
3684                if is_leap {
3685                    None
3686                } else {
3687                    linear.get(month_index)
3688                }
3689            }
3690            MonthNames::LeapLinear(leap_linear) => {
3691                let num_months = leap_linear.len() / 2;
3692                if is_leap {
3693                    leap_linear.get(month_index + num_months)
3694                } else if month_index < num_months {
3695                    leap_linear.get(month_index)
3696                } else {
3697                    None
3698                }
3699            }
3700            MonthNames::LeapNumeric(leap_numeric) => {
3701                if is_leap {
3702                    return Ok(MonthPlaceholderValue::NumericPattern(leap_numeric));
3703                } else {
3704                    return Ok(MonthPlaceholderValue::Numeric);
3705                }
3706            }
3707        };
3708        // Note: Always return `false` for the second argument since neo MonthNames
3709        // knows how to handle leap months and we don't need the fallback logic
3710        name.map(MonthPlaceholderValue::PlainString)
3711            .ok_or(GetNameForMonthError::InvalidMonthCode)
3712    }
3713
3714    pub(crate) fn get_name_for_weekday(
3715        &self,
3716        field_symbol: fields::Weekday,
3717        field_length: FieldLength,
3718        day: icu_calendar::types::Weekday,
3719    ) -> Result<&str, GetNameForWeekdayError> {
3720        let weekday_name_length = WeekdayNameLength::from_field(field_symbol, field_length)
3721            .ok_or(GetNameForWeekdayError::InvalidFieldLength)?;
3722        let weekday_names = self
3723            .weekday_names
3724            .get_with_variables(weekday_name_length)
3725            .ok_or(GetNameForWeekdayError::NotLoaded)?;
3726        weekday_names
3727            .names
3728            .get((day as usize) % 7)
3729            // Note: LinearNames does not guarantee a length of 7.
3730            .ok_or(GetNameForWeekdayError::NotLoaded)
3731    }
3732
3733    /// Gets the era symbol, or `None` if data is loaded but symbol isn't found.
3734    ///
3735    /// `None` should fall back to the era code directly, if, for example,
3736    /// a japanext datetime is formatted with a `DateTimeFormat<Japanese>`
3737    pub(crate) fn get_name_for_era(
3738        &self,
3739        field_length: FieldLength,
3740        era_year: EraYear,
3741    ) -> Result<&str, GetNameForEraError> {
3742        let year_name_length = YearNameLength::from_field_length(field_length)
3743            .ok_or(GetNameForEraError::InvalidFieldLength)?;
3744        let year_names = self
3745            .year_names
3746            .get_with_variables(year_name_length)
3747            .ok_or(GetNameForEraError::NotLoaded)?;
3748
3749        match (year_names, era_year.era_index) {
3750            (YearNames::VariableEras(era_names), None) => {
3751                crate::provider::neo::get_year_name_from_map(
3752                    era_names,
3753                    era_year.era.as_str().into(),
3754                )
3755                .ok_or(GetNameForEraError::InvalidEraCode)
3756            }
3757            (YearNames::FixedEras(era_names), Some(index)) => era_names
3758                .get(index as usize)
3759                .ok_or(GetNameForEraError::InvalidEraCode),
3760            _ => Err(GetNameForEraError::InvalidEraCode),
3761        }
3762    }
3763
3764    pub(crate) fn get_name_for_cyclic(
3765        &self,
3766        field_length: FieldLength,
3767        cyclic: u8,
3768    ) -> Result<&str, GetNameForCyclicYearError> {
3769        let year_name_length = YearNameLength::from_field_length(field_length)
3770            .ok_or(GetNameForCyclicYearError::InvalidFieldLength)?;
3771        let year_names = self
3772            .year_names
3773            .get_with_variables(year_name_length)
3774            .ok_or(GetNameForCyclicYearError::NotLoaded)?;
3775
3776        let YearNames::Cyclic(cyclics) = year_names else {
3777            return Err(GetNameForCyclicYearError::InvalidYearNumber { max: 0 });
3778        };
3779
3780        cyclics
3781            .get(cyclic as usize - 1)
3782            .ok_or(GetNameForCyclicYearError::InvalidYearNumber {
3783                max: cyclics.len() as u8 + 1,
3784            })
3785    }
3786
3787    pub(crate) fn get_name_for_day_period(
3788        &self,
3789        field_symbol: fields::DayPeriod,
3790        field_length: FieldLength,
3791        hour: icu_time::Hour,
3792        is_top_of_hour: bool,
3793    ) -> Result<&str, GetNameForDayPeriodError> {
3794        use fields::DayPeriod::NoonMidnight;
3795        let day_period_name_length = DayPeriodNameLength::from_field(field_symbol, field_length)
3796            .ok_or(GetNameForDayPeriodError::InvalidFieldLength)?;
3797        let dayperiod_names = self
3798            .dayperiod_names
3799            .get_with_variables(day_period_name_length)
3800            .ok_or(GetNameForDayPeriodError::NotLoaded)?;
3801        let option_value: Option<&str> = match (field_symbol, u8::from(hour), is_top_of_hour) {
3802            (NoonMidnight, 00, true) => dayperiod_names.midnight().or_else(|| dayperiod_names.am()),
3803            (NoonMidnight, 12, true) => dayperiod_names.noon().or_else(|| dayperiod_names.pm()),
3804            (_, hour, _) if hour < 12 => dayperiod_names.am(),
3805            _ => dayperiod_names.pm(),
3806        };
3807        option_value.ok_or(GetNameForDayPeriodError::NotLoaded)
3808    }
3809}
3810
3811/// A container contains all data payloads for time zone formatting (borrowed version).
3812#[derive(Debug, Copy, Clone, Default)]
3813pub(crate) struct TimeZoneDataPayloadsBorrowed<'a> {
3814    /// The data that contains meta information about how to display content.
3815    pub(crate) essentials: Option<&'a tz::Essentials<'a>>,
3816    /// The root location names, e.g. Italy
3817    pub(crate) locations_root: Option<&'a tz::Locations<'a>>,
3818    /// The language specific location names, e.g. Italia
3819    pub(crate) locations: Option<&'a tz::Locations<'a>>,
3820    /// The root exemplar city names, e.g. Rome
3821    pub(crate) exemplars_root: Option<&'a tz::ExemplarCities<'a>>,
3822    /// The language specific exemplar names, e.g. Roma
3823    pub(crate) exemplars: Option<&'a tz::ExemplarCities<'a>>,
3824    /// The generic long metazone names, e.g. Pacific Time
3825    pub(crate) mz_generic_long: Option<&'a tz::MzGeneric<'a>>,
3826    /// The long metazone names shared between generic and standard, e.g. Gulf Standard Time
3827    pub(crate) mz_standard_long: Option<&'a tz::MzGeneric<'a>>,
3828    /// The generic short metazone names, e.g. PT
3829    pub(crate) mz_generic_short: Option<&'a tz::MzGeneric<'a>>,
3830    /// The specific long metazone names, e.g. Pacific Daylight Time
3831    pub(crate) mz_specific_long: Option<&'a tz::MzSpecific<'a>>,
3832    /// The specific short metazone names, e.g. Pacific Daylight Time
3833    pub(crate) mz_specific_short: Option<&'a tz::MzSpecific<'a>>,
3834    /// The metazone lookup
3835    pub(crate) mz_periods: Option<&'a tz::MzPeriod<'a>>,
3836}
3837
3838impl<'data> RawDateTimeNamesBorrowed<'data> {
3839    pub(crate) fn get_payloads(&self) -> TimeZoneDataPayloadsBorrowed<'data> {
3840        TimeZoneDataPayloadsBorrowed {
3841            essentials: self.zone_essentials.get_option(),
3842            locations_root: self.locations_root.get_option(),
3843            locations: self.locations.get_option(),
3844            exemplars: self.exemplars.get_option(),
3845            exemplars_root: self.exemplars_root.get_option(),
3846            mz_generic_long: self.mz_generic_long.get_option(),
3847            mz_standard_long: self.mz_standard_long.get_option(),
3848            mz_generic_short: self.mz_generic_short.get_option(),
3849            mz_specific_long: self.mz_specific_long.get_option(),
3850            mz_specific_short: self.mz_specific_short.get_option(),
3851            mz_periods: self.mz_periods.get_option(),
3852        }
3853    }
3854}