• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zbraniecki / icu4x / 9014530096

08 May 2024 07:27PM UTC coverage: 76.402% (+0.2%) from 76.234%
9014530096

push

github

web-flow
Add missing std pointer-like impls for DataProvider, DynamicDataProvider (#4880)

0 of 3 new or added lines in 1 file covered. (0.0%)

3218 existing lines in 167 files now uncovered.

53328 of 69799 relevant lines covered (76.4%)

504343.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.12
/components/datetime/src/raw/datetime.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
//! The collection of code that is needed for handling formatting operations for DateTimes.
6
//! Central to this is the [`DateTimeFormatter`].
7

8
use crate::format::datetime::FormattedDateTime;
9
use crate::{
10
    format::datetime,
11
    input::{DateInput, DateTimeInput, ExtractedDateTimeInput, IsoTimeInput},
12
    options::{length, preferences},
13
    pattern::runtime::PatternPlurals,
14
    provider::{
15
        self,
16
        calendar::{
17
            patterns::GenericPatternV1Marker, patterns::PatternPluralsFromPatternsV1Marker,
18
            ErasedDateLengthsV1Marker, ErasedDateSymbolsV1Marker, TimeLengthsV1Marker,
19
            TimeSymbolsV1Marker,
20
        },
21
    },
22
    DateTimeError,
23
};
24

25
use icu_calendar::provider::WeekDataV1Marker;
26
use icu_calendar::week::WeekCalculator;
27
use icu_decimal::{
28
    options::{FixedDecimalFormatterOptions, GroupingStrategy},
29
    provider::DecimalSymbolsV1Marker,
30
    FixedDecimalFormatter,
31
};
32
use icu_plurals::{provider::OrdinalV1Marker, PluralRules};
33
use icu_provider::prelude::*;
34

UNCOV
35
#[derive(Debug)]
×
36
pub(crate) struct TimeFormatter {
37
    pub patterns: DataPayload<PatternPluralsFromPatternsV1Marker>,
×
38
    pub symbols: Option<DataPayload<TimeSymbolsV1Marker>>,
×
UNCOV
39
    pub fixed_decimal_format: FixedDecimalFormatter,
×
40
}
41

42
impl TimeFormatter {
43
    #[inline(never)]
44
    #[cfg(feature = "compiled_data")]
45
    pub fn try_new(
22✔
46
        locale: &DataLocale,
47
        length: length::Time,
48
        preferences: Option<preferences::Bag>,
49
    ) -> Result<Self, DateTimeError> {
50
        let patterns = provider::date_time::pattern_for_time_length(
22✔
51
            &crate::provider::Baked,
52
            locale,
53
            length,
54
            preferences,
UNCOV
55
        )?;
×
56

57
        let required = datetime::analyze_patterns(&patterns.get().0, false)
22✔
UNCOV
58
            .map_err(|field| DateTimeError::UnsupportedField(field.symbol))?;
×
59

60
        let symbols_data = if required.time_symbols_data {
37✔
61
            Some(
15✔
62
                crate::provider::Baked
15✔
63
                    .load(DataRequest {
15✔
64
                        locale,
65
                        metadata: Default::default(),
15✔
66
                    })?
×
UNCOV
67
                    .take_payload()?,
×
68
            )
UNCOV
69
        } else {
×
70
            None
7✔
71
        };
72

73
        let mut fixed_decimal_format_options = FixedDecimalFormatterOptions::default();
22✔
74
        fixed_decimal_format_options.grouping_strategy = GroupingStrategy::Never;
22✔
75

76
        let fixed_decimal_format =
77
            FixedDecimalFormatter::try_new(locale, fixed_decimal_format_options)?;
22✔
78

79
        Ok(Self::new(patterns, symbols_data, fixed_decimal_format))
22✔
80
    }
22✔
81

82
    #[inline(never)]
UNCOV
83
    pub fn try_new_unstable<D>(
×
84
        provider: &D,
85
        locale: &DataLocale,
86
        length: length::Time,
87
        preferences: Option<preferences::Bag>,
88
    ) -> Result<Self, DateTimeError>
89
    where
90
        D: DataProvider<TimeLengthsV1Marker>
91
            + DataProvider<TimeSymbolsV1Marker>
92
            + DataProvider<DecimalSymbolsV1Marker>
93
            + ?Sized,
94
    {
95
        let patterns =
×
UNCOV
96
            provider::date_time::pattern_for_time_length(provider, locale, length, preferences)?;
×
97

98
        let required = datetime::analyze_patterns(&patterns.get().0, false)
×
UNCOV
99
            .map_err(|field| DateTimeError::UnsupportedField(field.symbol))?;
×
100

101
        let symbols_data = if required.time_symbols_data {
×
102
            Some(
×
103
                provider
×
UNCOV
104
                    .load(DataRequest {
×
105
                        locale,
106
                        metadata: Default::default(),
×
107
                    })?
×
UNCOV
108
                    .take_payload()?,
×
109
            )
110
        } else {
×
UNCOV
111
            None
×
112
        };
113

114
        let mut fixed_decimal_format_options = FixedDecimalFormatterOptions::default();
×
UNCOV
115
        fixed_decimal_format_options.grouping_strategy = GroupingStrategy::Never;
×
116

UNCOV
117
        let fixed_decimal_format = FixedDecimalFormatter::try_new_unstable(
×
118
            provider,
119
            locale,
120
            fixed_decimal_format_options,
UNCOV
121
        )?;
×
122

123
        Ok(Self::new(patterns, symbols_data, fixed_decimal_format))
×
UNCOV
124
    }
×
125

126
    /// Creates a new [`TimeFormatter`] regardless of whether there are time-zone symbols in the pattern.
127
    pub fn new(
22✔
128
        patterns: DataPayload<PatternPluralsFromPatternsV1Marker>,
129
        symbols: Option<DataPayload<TimeSymbolsV1Marker>>,
130
        fixed_decimal_format: FixedDecimalFormatter,
131
    ) -> Self {
132
        Self {
22✔
133
            patterns,
22✔
134
            symbols,
22✔
135
            fixed_decimal_format,
22✔
136
        }
137
    }
22✔
138

139
    /// Takes a [`IsoTimeInput`] implementer and returns an instance of a [`FormattedDateTime`]
140
    /// that contains all information necessary to display a formatted date and operate on it.
141
    #[inline]
UNCOV
142
    pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l>
×
143
    where
144
        T: IsoTimeInput,
145
    {
146
        FormattedDateTime {
×
147
            patterns: &self.patterns,
×
148
            date_symbols: None,
×
149
            time_symbols: self.symbols.as_ref().map(|s| s.get()),
×
UNCOV
150
            datetime: ExtractedDateTimeInput::extract_from_time(value),
×
151
            week_data: None,
152
            ordinal_rules: None,
153
            fixed_decimal_format: &self.fixed_decimal_format,
154
        }
UNCOV
155
    }
×
156
}
157

UNCOV
158
#[derive(Debug)]
×
159
pub(crate) struct DateFormatter {
160
    pub generic_pattern: DataPayload<GenericPatternV1Marker>,
×
161
    pub patterns: DataPayload<PatternPluralsFromPatternsV1Marker>,
×
162
    pub symbols: Option<DataPayload<ErasedDateSymbolsV1Marker>>,
×
163
    pub week_data: Option<WeekCalculator>,
×
164
    pub ordinal_rules: Option<PluralRules>,
×
UNCOV
165
    pub fixed_decimal_format: FixedDecimalFormatter,
×
166
}
167

168
impl DateFormatter {
169
    #[cfg(feature = "compiled_data")]
170
    #[inline(never)]
171
    pub fn try_new(
4✔
172
        patterns_data: DataPayload<ErasedDateLengthsV1Marker>,
173
        symbols_data_fn: impl FnOnce() -> Result<DataPayload<ErasedDateSymbolsV1Marker>, DataError>,
174
        locale: &DataLocale,
175
        length: length::Date,
176
    ) -> Result<Self, DateTimeError> {
177
        let patterns = provider::date_time::pattern_for_date_length(length, patterns_data.clone());
4✔
178

179
        let generic_pattern =
180
            provider::date_time::generic_pattern_for_date_length(length, patterns_data);
4✔
181

182
        let required = datetime::analyze_patterns(&patterns.get().0, false)
4✔
UNCOV
183
            .map_err(|field| DateTimeError::UnsupportedField(field.symbol))?;
×
184

185
        let week_data = if required.week_data {
4✔
UNCOV
186
            Some(WeekCalculator::try_new(locale)?)
×
187
        } else {
188
            None
4✔
189
        };
190

191
        let ordinal_rules = if let PatternPlurals::MultipleVariants(_) = &patterns.get().0 {
4✔
192
            Some(PluralRules::try_new_ordinal(locale)?)
×
UNCOV
193
        } else {
×
194
            None
4✔
195
        };
196

197
        let symbols_data = if required.date_symbols_data {
8✔
198
            Some(symbols_data_fn()?)
4✔
199
        } else {
×
UNCOV
200
            None
×
201
        };
202

203
        let mut fixed_decimal_format_options = FixedDecimalFormatterOptions::default();
4✔
204
        fixed_decimal_format_options.grouping_strategy = GroupingStrategy::Never;
4✔
205

206
        let fixed_decimal_format =
207
            FixedDecimalFormatter::try_new(locale, fixed_decimal_format_options)?;
4✔
208

209
        Ok(Self::new(
4✔
210
            generic_pattern,
4✔
211
            patterns,
4✔
212
            symbols_data,
4✔
213
            week_data,
4✔
214
            ordinal_rules,
4✔
215
            fixed_decimal_format,
4✔
216
        ))
217
    }
4✔
218

219
    #[inline(never)]
220
    pub fn try_new_unstable<D>(
1✔
221
        provider: &D,
222
        patterns_data: DataPayload<ErasedDateLengthsV1Marker>,
223
        symbols_data_fn: impl FnOnce() -> Result<DataPayload<ErasedDateSymbolsV1Marker>, DataError>,
224
        locale: &DataLocale,
225
        length: length::Date,
226
    ) -> Result<Self, DateTimeError>
227
    where
228
        D: DataProvider<DecimalSymbolsV1Marker>
229
            + DataProvider<OrdinalV1Marker>
230
            + DataProvider<WeekDataV1Marker>
231
            + ?Sized,
232
    {
233
        let patterns = provider::date_time::pattern_for_date_length(length, patterns_data.clone());
1✔
234

235
        let generic_pattern =
236
            provider::date_time::generic_pattern_for_date_length(length, patterns_data);
1✔
237

238
        let required = datetime::analyze_patterns(&patterns.get().0, false)
1✔
UNCOV
239
            .map_err(|field| DateTimeError::UnsupportedField(field.symbol))?;
×
240

241
        let week_data = if required.week_data {
1✔
242
            Some(
×
UNCOV
243
                (*DataProvider::<WeekDataV1Marker>::load(
×
244
                    provider,
UNCOV
245
                    DataRequest {
×
246
                        locale,
UNCOV
247
                        metadata: Default::default(),
×
248
                    },
249
                )?
×
UNCOV
250
                .take_payload()?
×
251
                .get())
252
                .into(),
253
            )
UNCOV
254
        } else {
×
255
            None
1✔
256
        };
257

258
        let ordinal_rules = if let PatternPlurals::MultipleVariants(_) = &patterns.get().0 {
1✔
259
            Some(PluralRules::try_new_ordinal_unstable(provider, locale)?)
×
UNCOV
260
        } else {
×
261
            None
1✔
262
        };
263

264
        let symbols_data = if required.date_symbols_data {
2✔
265
            Some(symbols_data_fn()?)
1✔
266
        } else {
×
UNCOV
267
            None
×
268
        };
269

270
        let mut fixed_decimal_format_options = FixedDecimalFormatterOptions::default();
1✔
271
        fixed_decimal_format_options.grouping_strategy = GroupingStrategy::Never;
1✔
272

273
        let fixed_decimal_format = FixedDecimalFormatter::try_new_unstable(
1✔
274
            provider,
275
            locale,
276
            fixed_decimal_format_options,
UNCOV
277
        )?;
×
278

279
        Ok(Self::new(
1✔
280
            generic_pattern,
1✔
281
            patterns,
1✔
282
            symbols_data,
1✔
283
            week_data,
1✔
284
            ordinal_rules,
1✔
285
            fixed_decimal_format,
1✔
286
        ))
287
    }
1✔
288

289
    /// Creates a new [`DateTimeFormatter`] regardless of whether there are time-zone symbols in the pattern.
290
    pub fn new(
30✔
291
        generic_pattern: DataPayload<GenericPatternV1Marker>,
292
        patterns: DataPayload<PatternPluralsFromPatternsV1Marker>,
293
        symbols: Option<DataPayload<ErasedDateSymbolsV1Marker>>,
294
        week_data: Option<WeekCalculator>,
295
        ordinal_rules: Option<PluralRules>,
296
        fixed_decimal_format: FixedDecimalFormatter,
297
    ) -> Self {
298
        Self {
30✔
299
            generic_pattern,
30✔
300
            patterns,
30✔
301
            symbols,
30✔
302
            week_data,
30✔
303
            ordinal_rules,
30✔
304
            fixed_decimal_format,
30✔
305
        }
306
    }
30✔
307

308
    /// Takes a [`DateInput`] implementer and returns an instance of a [`FormattedDateTime`]
309
    /// that contains all information necessary to display a formatted date and operate on it.
310
    #[inline]
311
    pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l>
1✔
312
    where
313
        T: DateInput,
314
    {
315
        FormattedDateTime {
1✔
316
            patterns: &self.patterns,
1✔
317
            date_symbols: self.symbols.as_ref().map(|s| s.get()),
2✔
318
            time_symbols: None,
1✔
319
            datetime: ExtractedDateTimeInput::extract_from_date(value),
1✔
320
            week_data: None,
321
            ordinal_rules: None,
322
            fixed_decimal_format: &self.fixed_decimal_format,
323
        }
324
    }
1✔
325
}
326

327
/// This is the internal "raw" version of [`crate::DateTimeFormatter`], i.e. a version of `DateTimeFormatter`
328
/// without the generic parameter. The actual implementation of [`crate::DateTimeFormatter`] should live here.
UNCOV
329
#[derive(Debug)]
×
330
pub(crate) struct DateTimeFormatter {
331
    pub patterns: DataPayload<PatternPluralsFromPatternsV1Marker>,
×
332
    pub date_symbols: Option<DataPayload<ErasedDateSymbolsV1Marker>>,
×
333
    pub time_symbols: Option<DataPayload<TimeSymbolsV1Marker>>,
×
334
    pub week_data: Option<WeekCalculator>,
×
335
    pub ordinal_rules: Option<PluralRules>,
×
UNCOV
336
    pub fixed_decimal_format: FixedDecimalFormatter,
×
337
}
338

339
impl DateTimeFormatter {
340
    #[inline(never)]
341
    pub fn try_from_date_and_time(
17✔
342
        date: DateFormatter,
343
        time: TimeFormatter,
344
    ) -> Result<Self, DateTimeError> {
345
        let generic_pattern = &date.generic_pattern;
17✔
346
        let time_patterns = &time.patterns;
17✔
347
        let patterns = date
34✔
348
            .patterns
349
            .try_map_project::<PatternPluralsFromPatternsV1Marker, _, DateTimeError>(
350
                |data, _| {
34✔
351
                    let date_pattern = data.0.expect_pattern("Lengths are single patterns");
17✔
352
                    let time_pattern: crate::pattern::runtime::Pattern = time_patterns
17✔
353
                        .get()
354
                        .clone()
355
                        .0
356
                        .expect_pattern("Lengths are single patterns");
357

358
                    Ok(PatternPlurals::from(
17✔
359
                        generic_pattern
17✔
360
                            .get()
361
                            .clone()
362
                            .0
363
                            .combined(date_pattern, time_pattern)?,
17✔
364
                    )
365
                    .into())
366
                },
17✔
UNCOV
367
            )?;
×
368

369
        Ok(Self {
17✔
370
            patterns,
17✔
371
            date_symbols: date.symbols,
17✔
372
            time_symbols: time.symbols,
17✔
373
            week_data: date.week_data,
17✔
374
            ordinal_rules: date.ordinal_rules,
17✔
375
            fixed_decimal_format: date.fixed_decimal_format,
17✔
376
        })
377
    }
17✔
378

379
    #[inline(never)]
380
    #[cfg(feature = "compiled_data")]
381
    pub fn try_new(
181✔
382
        patterns: DataPayload<PatternPluralsFromPatternsV1Marker>,
383
        symbols_data_fn: impl FnOnce() -> Result<DataPayload<ErasedDateSymbolsV1Marker>, DataError>,
384
        locale: &DataLocale,
385
    ) -> Result<Self, DateTimeError> {
386
        let required = datetime::analyze_patterns(&patterns.get().0, false)
181✔
UNCOV
387
            .map_err(|field| DateTimeError::UnsupportedField(field.symbol))?;
×
388

389
        let req = DataRequest {
181✔
390
            locale,
391
            metadata: Default::default(),
181✔
392
        };
393

394
        let week_data = if required.week_data {
193✔
395
            Some(WeekCalculator::try_new(locale)?)
12✔
396
        } else {
397
            None
169✔
398
        };
399

400
        let ordinal_rules = if let PatternPlurals::MultipleVariants(_) = &patterns.get().0 {
184✔
401
            Some(PluralRules::try_new_ordinal(locale)?)
3✔
UNCOV
402
        } else {
×
403
            None
178✔
404
        };
405

406
        let date_symbols_data = if required.date_symbols_data {
311✔
407
            Some(symbols_data_fn()?)
130✔
UNCOV
408
        } else {
×
409
            None
51✔
410
        };
411

412
        let time_symbols_data = if required.time_symbols_data {
208✔
413
            Some(crate::provider::Baked.load(req)?.take_payload()?)
27✔
UNCOV
414
        } else {
×
415
            None
154✔
416
        };
417

418
        let mut fixed_decimal_format_options = FixedDecimalFormatterOptions::default();
181✔
419
        fixed_decimal_format_options.grouping_strategy = GroupingStrategy::Never;
181✔
420

421
        let fixed_decimal_format =
422
            FixedDecimalFormatter::try_new(locale, fixed_decimal_format_options)?;
181✔
423

424
        Ok(Self::new(
181✔
425
            patterns,
181✔
426
            date_symbols_data,
181✔
427
            time_symbols_data,
181✔
428
            week_data,
181✔
429
            ordinal_rules,
181✔
430
            fixed_decimal_format,
181✔
431
        ))
432
    }
181✔
433

434
    #[inline(never)]
435
    pub fn try_new_unstable<D>(
1✔
436
        provider: &D,
437
        patterns: DataPayload<PatternPluralsFromPatternsV1Marker>,
438
        symbols_data_fn: impl FnOnce() -> Result<DataPayload<ErasedDateSymbolsV1Marker>, DataError>,
439
        locale: &DataLocale,
440
    ) -> Result<Self, DateTimeError>
441
    where
442
        D: DataProvider<TimeSymbolsV1Marker>
443
            + DataProvider<TimeLengthsV1Marker>
444
            + DataProvider<DecimalSymbolsV1Marker>
445
            + DataProvider<OrdinalV1Marker>
446
            + DataProvider<WeekDataV1Marker>
447
            + ?Sized,
448
    {
449
        let required = datetime::analyze_patterns(&patterns.get().0, false)
1✔
UNCOV
450
            .map_err(|field| DateTimeError::UnsupportedField(field.symbol))?;
×
451

452
        let req = DataRequest {
1✔
453
            locale,
454
            metadata: Default::default(),
1✔
455
        };
456

457
        let week_data = if required.week_data {
1✔
458
            Some(
×
UNCOV
459
                (*DataProvider::<WeekDataV1Marker>::load(
×
460
                    provider,
UNCOV
461
                    DataRequest {
×
462
                        locale,
UNCOV
463
                        metadata: Default::default(),
×
464
                    },
465
                )?
×
UNCOV
466
                .take_payload()?
×
467
                .get())
468
                .into(),
469
            )
UNCOV
470
        } else {
×
471
            None
1✔
472
        };
473

474
        let ordinal_rules = if let PatternPlurals::MultipleVariants(_) = &patterns.get().0 {
1✔
475
            Some(PluralRules::try_new_ordinal_unstable(provider, locale)?)
×
UNCOV
476
        } else {
×
477
            None
1✔
478
        };
479

480
        let date_symbols_data = if required.date_symbols_data {
2✔
481
            Some(symbols_data_fn()?)
1✔
482
        } else {
×
UNCOV
483
            None
×
484
        };
485

486
        let time_symbols_data = if required.time_symbols_data {
2✔
487
            Some(provider.load(req)?.take_payload()?)
1✔
488
        } else {
×
UNCOV
489
            None
×
490
        };
491

492
        let mut fixed_decimal_format_options = FixedDecimalFormatterOptions::default();
1✔
493
        fixed_decimal_format_options.grouping_strategy = GroupingStrategy::Never;
1✔
494

495
        let fixed_decimal_format = FixedDecimalFormatter::try_new_unstable(
1✔
496
            provider,
497
            locale,
498
            fixed_decimal_format_options,
UNCOV
499
        )?;
×
500

501
        Ok(Self::new(
1✔
502
            patterns,
1✔
503
            date_symbols_data,
1✔
504
            time_symbols_data,
1✔
505
            week_data,
1✔
506
            ordinal_rules,
1✔
507
            fixed_decimal_format,
1✔
508
        ))
509
    }
1✔
510

511
    /// Creates a new [`DateTimeFormatter`] regardless of whether there are time-zone symbols in the pattern.
512
    pub fn new(
694✔
513
        patterns: DataPayload<PatternPluralsFromPatternsV1Marker>,
514
        date_symbols: Option<DataPayload<ErasedDateSymbolsV1Marker>>,
515
        time_symbols: Option<DataPayload<TimeSymbolsV1Marker>>,
516
        week_data: Option<WeekCalculator>,
517
        ordinal_rules: Option<PluralRules>,
518
        fixed_decimal_format: FixedDecimalFormatter,
519
    ) -> Self {
520
        Self {
694✔
521
            patterns,
694✔
522
            date_symbols,
694✔
523
            time_symbols,
694✔
524
            week_data,
694✔
525
            ordinal_rules,
694✔
526
            fixed_decimal_format,
694✔
527
        }
528
    }
694✔
529

530
    /// Takes a [`DateTimeInput`] implementer and returns an instance of a [`FormattedDateTime`]
531
    /// that contains all information necessary to display a formatted date and operate on it.
532
    #[inline]
533
    pub fn format<'l, T>(&'l self, value: &T) -> FormattedDateTime<'l>
9✔
534
    where
535
        T: DateTimeInput,
536
    {
537
        // Todo: optimize extraction #2143
538
        FormattedDateTime {
9✔
539
            patterns: &self.patterns,
9✔
540
            date_symbols: self.date_symbols.as_ref().map(|s| s.get()),
18✔
541
            time_symbols: self.time_symbols.as_ref().map(|s| s.get()),
11✔
542
            datetime: ExtractedDateTimeInput::extract_from(value),
9✔
543
            week_data: self.week_data.as_ref(),
9✔
544
            ordinal_rules: self.ordinal_rules.as_ref(),
9✔
545
            fixed_decimal_format: &self.fixed_decimal_format,
546
        }
547
    }
9✔
548

549
    /// Returns a [`components::Bag`](crate::options::components::Bag) that represents the resolved components for the
550
    /// options that were provided to the [`DateTimeFormatter`].
551
    #[cfg(feature = "experimental")]
552
    pub fn resolve_components(&self) -> crate::options::components::Bag {
6✔
553
        crate::options::components::Bag::from(&self.patterns.get().0)
6✔
554
    }
6✔
555
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc