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

zbraniecki / icu4x / 6815798908

09 Nov 2023 05:17PM UTC coverage: 72.607% (-2.4%) from 75.01%
6815798908

push

github

web-flow
Implement `Any/BufferProvider` for some smart pointers (#4255)

Allows storing them as a `Box<dyn Any/BufferProvider>` without using a
wrapper type that implements the trait.

44281 of 60987 relevant lines covered (72.61%)

201375.86 hits per line

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

93.22
/components/datetime/src/skeleton/reference.rs
1
// This file is part of ICU4X. For terms of use, please see the file
1✔
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
use super::error::SkeletonError;
6
use crate::fields::{self, Field, FieldLength, FieldSymbol};
7
#[cfg(feature = "datagen")]
8
use crate::pattern::reference::Pattern;
9
use alloc::vec::Vec;
10
use core::convert::TryFrom;
11
use smallvec::SmallVec;
12

13
/// A [`Skeleton`] is used to represent what types of `Field`s are present in a [`Pattern`]. The
14
/// ordering of the [`Skeleton`]'s `Field`s have no bearing on the ordering of the `Field`s and
15
/// `Literal`s in the [`Pattern`].
16
///
17
/// A [`Skeleton`] is a [`Vec`]`<Field>`, but with the invariant that it is sorted according to the canonical
18
/// sort order. This order is sorted according to the most significant `Field` to the least significant.
19
/// For example, a field with a `Minute` symbol would precede a field with a `Second` symbol.
20
/// This order is documented as the order of fields as presented in the
21
/// [UTS 35 Date Field Symbol Table](https://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table)
22
///
23
/// The `Field`s are only sorted in the [`Skeleton`] in order to provide a deterministic
24
/// serialization strategy, and to provide a faster [`Skeleton`] matching operation.
25
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd)]
46,030✔
26
// TODO(#876): Use ZeroVec instead of SmallVec
27
pub struct Skeleton(pub(crate) SmallVec<[fields::Field; 5]>);
23,015✔
28

29
impl Skeleton {
30
    pub(crate) fn fields_iter(&self) -> impl Iterator<Item = &Field> {
18,536✔
31
        self.0.iter()
18,536✔
32
    }
18,536✔
33

34
    pub(crate) fn fields_len(&self) -> usize {
18,490✔
35
        self.0.len()
18,490✔
36
    }
18,490✔
37

38
    /// Return the underlying fields as a slice.
39
    pub fn as_slice(&self) -> &[fields::Field] {
×
40
        self.0.as_slice()
×
41
    }
×
42
}
43

44
impl From<SmallVec<[fields::Field; 5]>> for Skeleton {
45
    fn from(fields: SmallVec<[fields::Field; 5]>) -> Self {
177✔
46
        Self(fields)
177✔
47
    }
177✔
48
}
49

50
impl From<Vec<fields::Field>> for Skeleton {
51
    fn from(fields: Vec<fields::Field>) -> Self {
1✔
52
        Self(fields.into())
1✔
53
    }
1✔
54
}
55

56
impl From<&[fields::Field]> for Skeleton {
57
    fn from(fields: &[fields::Field]) -> Self {
12,362✔
58
        Self(fields.into())
12,362✔
59
    }
12,362✔
60
}
61

62
/// Convert a Pattern into a Skeleton. This will remove all of the string literals, and sort
63
/// the fields into the canonical sort order. Not all fields are supported by Skeletons, so map
64
/// fields into skeleton-appropriate ones. For instance, in the "ja" locale the pattern "aK:mm"
65
/// gets transformed into the skeleton "hmm".
66
///
67
/// At the time of this writing, it's being used for applying hour cycle preferences and should not
68
/// be exposed as a public API for end users.
69
#[doc(hidden)]
70
#[cfg(feature = "datagen")]
71
impl From<&Pattern> for Skeleton {
72
    fn from(pattern: &Pattern) -> Self {
19✔
73
        let mut fields: SmallVec<[fields::Field; 5]> = SmallVec::new();
19✔
74
        for item in pattern.items() {
64✔
75
            if let crate::pattern::PatternItem::Field(field) = item {
45✔
76
                let mut field = *field;
31✔
77

78
                // Skeletons only have a subset of available fields, these are then mapped to more
79
                // specific fields for the patterns they expand to.
80
                field.symbol = match field.symbol {
60✔
81
                    // Only the format varieties are used in the skeletons, the matched patterns
82
                    // will be more specific.
83
                    FieldSymbol::Month(_) => FieldSymbol::Month(fields::Month::Format),
1✔
84
                    FieldSymbol::Weekday(_) => FieldSymbol::Weekday(fields::Weekday::Format),
×
85

86
                    // Only flexible day periods are used in skeletons, ignore all others.
87
                    FieldSymbol::DayPeriod(fields::DayPeriod::AmPm)
88
                    | FieldSymbol::DayPeriod(fields::DayPeriod::NoonMidnight) => continue,
89
                    // TODO(#487) - Flexible day periods should be included here.
90
                    // FieldSymbol::DayPeriod(fields::DayPeriod::Flexible) => {
91
                    //     FieldSymbol::DayPeriod(fields::DayPeriod::Flexible)
92
                    // }
93

94
                    // Only the H12 and H23 symbols are used in skeletons, while the patterns may
95
                    // contain H11 or H23 depending on the localization.
96
                    FieldSymbol::Hour(fields::Hour::H11) | FieldSymbol::Hour(fields::Hour::H12) => {
97
                        FieldSymbol::Hour(fields::Hour::H12)
3✔
98
                    }
99
                    FieldSymbol::Hour(fields::Hour::H23) | FieldSymbol::Hour(fields::Hour::H24) => {
100
                        FieldSymbol::Hour(fields::Hour::H23)
3✔
101
                    }
102

103
                    // Pass through all of the following preferences unchanged.
104
                    FieldSymbol::Minute
105
                    | FieldSymbol::Second(_)
106
                    | FieldSymbol::TimeZone(_)
107
                    | FieldSymbol::Era
108
                    | FieldSymbol::Year(_)
109
                    | FieldSymbol::Week(_)
110
                    | FieldSymbol::Day(_) => field.symbol,
22✔
111
                };
112

113
                // Only insert if it's a unique field.
114
                if let Err(pos) = fields.binary_search(&field) {
29✔
115
                    fields.insert(pos, field)
29✔
116
                }
117
            }
118
        }
119
        Self(fields)
19✔
120
    }
19✔
121
}
122

123
/// Parse a string into a list of fields. This trait implementation validates the input string to
124
/// verify that fields are correct. If the fields are out of order, this returns an error that
125
/// contains the fields, which gives the callee a chance to sort the fields with the
126
/// `From<SmallVec<[fields::Field; 5]>> for Skeleton` trait.
127
impl TryFrom<&str> for Skeleton {
128
    type Error = SkeletonError;
129
    fn try_from(skeleton_string: &str) -> Result<Self, Self::Error> {
193✔
130
        let mut fields: SmallVec<[fields::Field; 5]> = SmallVec::new();
193✔
131

132
        let mut iter = skeleton_string.chars().peekable();
193✔
133
        while let Some(ch) = iter.next() {
645✔
134
            // Convert the byte to a valid field symbol.
135
            let field_symbol = FieldSymbol::try_from(ch)?;
468✔
136

137
            // Go through the chars to count how often it's repeated.
138
            let mut field_length: u8 = 1;
453✔
139
            while let Some(next_ch) = iter.peek() {
660✔
140
                if *next_ch != ch {
482✔
141
                    break;
142
                }
143
                field_length += 1;
207✔
144
                iter.next();
207✔
145
            }
146

147
            let field = Field::from((field_symbol, FieldLength::from_idx(field_length)?));
453✔
148

149
            match fields.binary_search(&field) {
453✔
150
                Ok(_) => return Err(SkeletonError::DuplicateField),
1✔
151
                Err(pos) => fields.insert(pos, field),
452✔
152
            }
153
        }
154

155
        Ok(Self::from(fields))
177✔
156
    }
193✔
157
}
158

159
#[cfg(feature = "datagen")]
160
impl core::fmt::Display for Skeleton {
161
    fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
40✔
162
        use core::fmt::Write;
163
        for field in self.fields_iter() {
115✔
164
            let ch: char = field.symbol.into();
75✔
165
            for _ in 0..field.length.to_len() {
174✔
166
                formatter.write_char(ch)?;
99✔
167
            }
168
        }
169
        Ok(())
40✔
170
    }
40✔
171
}
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

© 2025 Coveralls, Inc