icu_capi/
datetime_helpers.rs

1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5#![allow(dead_code)] // features in here are a mess
6
7use alloc::boxed::Box;
8use icu_calendar::Gregorian;
9use icu_datetime::{
10    fieldsets::builder::BuilderError, fieldsets::enums::*, fieldsets::Combo, pattern::*,
11    scaffold::*, DateTimeFormatter, DateTimeFormatterLoadError, FixedCalendarDateTimeFormatter,
12};
13
14pub(crate) fn map_or_default<Input, Output>(input: Option<Input>) -> Output
15where
16    Output: From<Input> + Default,
17{
18    input.map(Output::from).unwrap_or_default()
19}
20
21pub(super) fn date_formatter_with_zone<Zone>(
22    formatter: &DateTimeFormatter<DateFieldSet>,
23    locale: &crate::locale_core::ffi::Locale,
24    zone: Zone,
25    load: impl FnOnce(
26        &mut DateTimeNames<Combo<DateFieldSet, Zone>>,
27    ) -> Result<(), crate::errors::ffi::DateTimeFormatterLoadError>,
28    to_formatter: impl FnOnce(
29        DateTimeNames<Combo<DateFieldSet, Zone>>,
30        Combo<DateFieldSet, Zone>,
31    ) -> Result<
32        DateTimeFormatter<Combo<DateFieldSet, Zone>>,
33        (
34            DateTimeFormatterLoadError,
35            DateTimeNames<Combo<DateFieldSet, Zone>>,
36        ),
37    >,
38) -> Result<
39    Box<crate::zoned_date_formatter::ffi::ZonedDateFormatter>,
40    crate::errors::ffi::DateTimeFormatterLoadError,
41>
42where
43    Zone: DateTimeMarkers + ZoneMarkers,
44    <Zone as DateTimeMarkers>::Z: ZoneMarkers,
45    Combo<DateFieldSet, Zone>: DateTimeNamesFrom<DateFieldSet>,
46    ZonedDateFieldSet: DateTimeNamesFrom<Combo<DateFieldSet, Zone>>,
47{
48    let prefs = (&locale.0).into();
49    let mut names = DateTimeNames::from_formatter(prefs, formatter.clone())
50        .cast_into_fset::<Combo<DateFieldSet, Zone>>();
51    load(&mut names)?;
52    let field_set = formatter
53        .to_field_set_builder()
54        .build_date()
55        .map_err(|e| match e {
56            BuilderError::InvalidDateFields => {
57                // This can fail if the date fields are for a calendar period
58                crate::errors::ffi::DateTimeFormatterLoadError::InvalidDateFields
59            }
60            _ => {
61                debug_assert!(false, "should be infallible, but got: {e:?}");
62                crate::errors::ffi::DateTimeFormatterLoadError::Unknown
63            }
64        })?
65        .zone(zone);
66    let formatter = to_formatter(names, field_set)
67        // This can fail if the locale doesn't match and the fields conflict
68        .map_err(|(e, _)| e)?
69        .cast_into_fset();
70    Ok(Box::new(
71        crate::zoned_date_formatter::ffi::ZonedDateFormatter(formatter),
72    ))
73}
74
75pub(super) fn datetime_formatter_with_zone<Zone>(
76    formatter: &DateTimeFormatter<CompositeDateTimeFieldSet>,
77    locale: &crate::locale_core::ffi::Locale,
78    zone: Zone,
79    load: impl FnOnce(
80        &mut DateTimeNames<Combo<DateAndTimeFieldSet, Zone>>,
81    ) -> Result<(), crate::errors::ffi::DateTimeFormatterLoadError>,
82    to_formatter: impl FnOnce(
83        DateTimeNames<Combo<DateAndTimeFieldSet, Zone>>,
84        Combo<DateAndTimeFieldSet, Zone>,
85    ) -> Result<
86        DateTimeFormatter<Combo<DateAndTimeFieldSet, Zone>>,
87        (
88            DateTimeFormatterLoadError,
89            DateTimeNames<Combo<DateAndTimeFieldSet, Zone>>,
90        ),
91    >,
92) -> Result<
93    Box<crate::zoned_date_time_formatter::ffi::ZonedDateTimeFormatter>,
94    crate::errors::ffi::DateTimeFormatterLoadError,
95>
96where
97    Zone: DateTimeMarkers + ZoneMarkers,
98    <Zone as DateTimeMarkers>::Z: ZoneMarkers,
99    Combo<DateAndTimeFieldSet, Zone>: DateTimeNamesFrom<CompositeDateTimeFieldSet>,
100    ZonedDateAndTimeFieldSet: DateTimeNamesFrom<Combo<DateAndTimeFieldSet, Zone>>,
101{
102    let prefs = (&locale.0).into();
103    let mut names = DateTimeNames::from_formatter(prefs, formatter.clone())
104        .cast_into_fset::<Combo<DateAndTimeFieldSet, Zone>>();
105    load(&mut names)?;
106    let field_set = formatter
107        .to_field_set_builder()
108        .build_date_and_time()
109        .map_err(|e| match e {
110            BuilderError::InvalidDateFields => {
111                debug_assert!(false, "fields were already validated in DateTimeFormatter");
112                crate::errors::ffi::DateTimeFormatterLoadError::InvalidDateFields
113            }
114            _ => {
115                debug_assert!(false, "should be infallible, but got: {e:?}");
116                crate::errors::ffi::DateTimeFormatterLoadError::Unknown
117            }
118        })?
119        .zone(zone);
120    let formatter = to_formatter(names, field_set)
121        // This can fail if the locale doesn't match and the fields conflict
122        .map_err(|(e, _)| e)?
123        .cast_into_fset();
124    Ok(Box::new(
125        crate::zoned_date_time_formatter::ffi::ZonedDateTimeFormatter(formatter),
126    ))
127}
128
129pub(super) fn date_formatter_gregorian_with_zone<Zone>(
130    formatter: &FixedCalendarDateTimeFormatter<Gregorian, DateFieldSet>,
131    locale: &crate::locale_core::ffi::Locale,
132    zone: Zone,
133    load: impl FnOnce(
134        &mut FixedCalendarDateTimeNames<Gregorian, Combo<DateFieldSet, Zone>>,
135    ) -> Result<(), crate::errors::ffi::DateTimeFormatterLoadError>,
136    to_formatter: impl FnOnce(
137        FixedCalendarDateTimeNames<Gregorian, Combo<DateFieldSet, Zone>>,
138        Combo<DateFieldSet, Zone>,
139    ) -> Result<
140        FixedCalendarDateTimeFormatter<Gregorian, Combo<DateFieldSet, Zone>>,
141        (
142            DateTimeFormatterLoadError,
143            FixedCalendarDateTimeNames<Gregorian, Combo<DateFieldSet, Zone>>,
144        ),
145    >,
146) -> Result<
147    Box<crate::zoned_date_formatter::ffi::ZonedDateFormatterGregorian>,
148    crate::errors::ffi::DateTimeFormatterLoadError,
149>
150where
151    Zone: DateTimeMarkers + ZoneMarkers,
152    <Zone as DateTimeMarkers>::Z: ZoneMarkers,
153    Combo<DateFieldSet, Zone>: DateTimeNamesFrom<DateFieldSet>,
154    ZonedDateFieldSet: DateTimeNamesFrom<Combo<DateFieldSet, Zone>>,
155{
156    let prefs = (&locale.0).into();
157    let mut names = FixedCalendarDateTimeNames::from_formatter(prefs, formatter.clone())
158        .cast_into_fset::<Combo<DateFieldSet, Zone>>();
159    load(&mut names)?;
160    let field_set = formatter
161        .to_field_set_builder()
162        .build_date()
163        .map_err(|e| match e {
164            BuilderError::InvalidDateFields => {
165                // This can fail if the date fields are for a calendar period
166                crate::errors::ffi::DateTimeFormatterLoadError::InvalidDateFields
167            }
168            _ => {
169                debug_assert!(false, "should be infallible, but got: {e:?}");
170                crate::errors::ffi::DateTimeFormatterLoadError::Unknown
171            }
172        })?
173        .zone(zone);
174    let formatter = to_formatter(names, field_set)
175        // This can fail if the locale doesn't match and the fields conflict
176        .map_err(|(e, _)| e)?
177        .cast_into_fset();
178    Ok(Box::new(
179        crate::zoned_date_formatter::ffi::ZonedDateFormatterGregorian(formatter),
180    ))
181}
182
183pub(super) fn datetime_formatter_gregorian_with_zone<Zone>(
184    formatter: &FixedCalendarDateTimeFormatter<Gregorian, CompositeDateTimeFieldSet>,
185    locale: &crate::locale_core::ffi::Locale,
186    zone: Zone,
187    load: impl FnOnce(
188        &mut FixedCalendarDateTimeNames<Gregorian, Combo<DateAndTimeFieldSet, Zone>>,
189    ) -> Result<(), crate::errors::ffi::DateTimeFormatterLoadError>,
190    to_formatter: impl FnOnce(
191        FixedCalendarDateTimeNames<Gregorian, Combo<DateAndTimeFieldSet, Zone>>,
192        Combo<DateAndTimeFieldSet, Zone>,
193    ) -> Result<
194        FixedCalendarDateTimeFormatter<Gregorian, Combo<DateAndTimeFieldSet, Zone>>,
195        (
196            DateTimeFormatterLoadError,
197            FixedCalendarDateTimeNames<Gregorian, Combo<DateAndTimeFieldSet, Zone>>,
198        ),
199    >,
200) -> Result<
201    Box<crate::zoned_date_time_formatter::ffi::ZonedDateTimeFormatterGregorian>,
202    crate::errors::ffi::DateTimeFormatterLoadError,
203>
204where
205    Zone: DateTimeMarkers + ZoneMarkers,
206    <Zone as DateTimeMarkers>::Z: ZoneMarkers,
207    Combo<DateAndTimeFieldSet, Zone>: DateTimeNamesFrom<CompositeDateTimeFieldSet>,
208    ZonedDateAndTimeFieldSet: DateTimeNamesFrom<Combo<DateAndTimeFieldSet, Zone>>,
209{
210    let prefs = (&locale.0).into();
211    let mut names = FixedCalendarDateTimeNames::from_formatter(prefs, formatter.clone())
212        .cast_into_fset::<Combo<DateAndTimeFieldSet, Zone>>();
213    load(&mut names)?;
214    let field_set = formatter
215        .to_field_set_builder()
216        .build_date_and_time()
217        .map_err(|e| match e {
218            BuilderError::InvalidDateFields => {
219                debug_assert!(false, "fields were already validated in DateTimeFormatter");
220                crate::errors::ffi::DateTimeFormatterLoadError::InvalidDateFields
221            }
222            _ => {
223                debug_assert!(false, "should be infallible, but got: {e:?}");
224                crate::errors::ffi::DateTimeFormatterLoadError::Unknown
225            }
226        })?
227        .zone(zone);
228    let formatter = to_formatter(names, field_set)
229        // This can fail if the locale doesn't match and the fields conflict
230        .map_err(|(e, _)| e)?
231        .cast_into_fset();
232    Ok(Box::new(
233        crate::zoned_date_time_formatter::ffi::ZonedDateTimeFormatterGregorian(formatter),
234    ))
235}