• 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

63.22
/components/datetime/src/fields/length.rs
1
// This file is part of ICU4X. For terms of use, please see the file
2✔
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 core::cmp::{Ord, PartialOrd};
6
use core::fmt;
7
use displaydoc::Display;
8
use zerovec::ule::{AsULE, ZeroVecError, ULE};
9

10
#[cfg(doc)]
11
use crate::fields::{Hour, Weekday};
12

13
/// An error relating to the length of a field within a date pattern.
14
#[derive(Display, Debug, PartialEq, Copy, Clone)]
×
15
#[non_exhaustive]
16
pub enum LengthError {
17
    /// The length of the field string within the pattern is invalid, according to
18
    /// the field type and its supported field patterns in LDML. See [`FieldLength`].
19
    #[displaydoc("Invalid length")]
20
    InvalidLength,
21
}
22

23
#[cfg(feature = "std")]
24
impl std::error::Error for LengthError {}
25

26
/// An enum representing the length of a field within a date or time formatting pattern string,
27
/// in which the pattern field is represented as a letter occurring 1 or more times in a row, ex:
28
/// `MMM`, `dd`, `y`.  See the
29
/// [LDML documentation in UTS 35](https://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns)
30
/// for more details.
31
#[derive(Debug, Eq, PartialEq, Clone, Copy, Ord, PartialOrd)]
40,841✔
32
#[cfg_attr(
33
    feature = "datagen",
34
    derive(serde::Serialize, databake::Bake),
10✔
35
    databake(path = icu_datetime::fields),
36
)]
37
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
20✔
38
#[allow(clippy::exhaustive_enums)] // part of data struct
39
pub enum FieldLength {
5✔
40
    /// Typical style is 1-2 digits. For numeric-only fields.
41
    One,
42
    /// Typical style is 2 digits. For numeric-only fields.
43
    TwoDigit,
44
    /// Abbreviated (spellout) format.
45
    Abbreviated,
46
    /// Wide / Long / Full  (spellout) format.
47
    Wide,
48
    /// Narrow / Long / Full  (spellout) format.
49
    Narrow,
50
    /// Meaning is field-dependent, for patterns that are 6 characters long. Ex: a [`Weekday`] pattern like
51
    /// `EEEEEE` means "Short", but `jjjjjj` or `CCCCCC` for [`Hour`] may mean
52
    /// "Numeric hour (2 digits, zero pad if needed), narrow dayPeriod if used". See the
53
    /// [LDML documentation in UTS 35](https://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns)
54
    /// for more details.
55
    Six,
56
    /// A fixed size format for numeric-only fields that is at most 127 digits.
57
    Fixed(u8),
53✔
58
    /// FieldLength::One (numeric), but overridden with a different numbering system
59
    NumericOverride(FieldNumericOverrides),
×
60
}
61

62
impl FieldLength {
63
    #[inline]
64
    pub(crate) fn idx(&self) -> u8 {
3,310✔
65
        match self {
3,310✔
66
            FieldLength::One => 1,
1,115✔
67
            FieldLength::TwoDigit => 2,
973✔
68
            FieldLength::Abbreviated => 3,
197✔
69
            FieldLength::Wide => 4,
863✔
70
            FieldLength::Narrow => 5,
100✔
71
            FieldLength::Six => 6,
54✔
72
            FieldLength::NumericOverride(o) => 64 + (*o as u8).min(63),
×
73
            FieldLength::Fixed(p) => 128 + p.min(&127), /* truncate to at most 127 digits to avoid overflow */
8✔
74
        }
75
    }
3,310✔
76

77
    #[inline]
78
    pub(crate) fn from_idx(idx: u8) -> Result<Self, LengthError> {
16,558✔
79
        Ok(match idx {
33,114✔
80
            1 => Self::One,
7,644✔
81
            2 => Self::TwoDigit,
4,733✔
82
            3 => Self::Abbreviated,
1,051✔
83
            4 => Self::Wide,
2,567✔
84
            5 => Self::Narrow,
380✔
85
            6 => Self::Six,
131✔
86
            idx => {
52✔
87
                if idx < 64 {
52✔
88
                    return Err(LengthError::InvalidLength);
2✔
89
                }
90
                if idx < 128 {
50✔
91
                    Self::NumericOverride((idx - 64).try_into()?)
×
92
                } else {
93
                    Self::Fixed(idx - 128)
50✔
94
                }
95
            }
96
        })
97
    }
16,558✔
98

99
    #[inline]
100
    #[cfg(feature = "datagen")]
101
    pub(crate) fn to_len(self) -> usize {
219✔
102
        match self {
219✔
103
            FieldLength::One => 1,
118✔
104
            FieldLength::TwoDigit => 2,
46✔
105
            FieldLength::Abbreviated => 3,
16✔
106
            FieldLength::Wide => 4,
17✔
107
            FieldLength::Narrow => 5,
13✔
108
            FieldLength::Six => 6,
2✔
109
            FieldLength::NumericOverride(o) => 64 + o as usize,
×
110
            FieldLength::Fixed(p) => p as usize,
7✔
111
        }
112
    }
219✔
113
}
114

115
#[repr(transparent)]
116
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
×
117
pub struct FieldLengthULE(u8);
×
118

119
impl AsULE for FieldLength {
120
    type ULE = FieldLengthULE;
121
    fn to_unaligned(self) -> Self::ULE {
6✔
122
        FieldLengthULE(self.idx())
6✔
123
    }
6✔
124
    fn from_unaligned(unaligned: Self::ULE) -> Self {
4✔
125
        #[allow(clippy::unwrap_used)] // OK because the ULE is pre-validated
126
        Self::from_idx(unaligned.0).unwrap()
4✔
127
    }
4✔
128
}
129

130
impl FieldLengthULE {
131
    #[inline]
132
    pub(crate) fn validate_byte(byte: u8) -> Result<(), ZeroVecError> {
119✔
133
        FieldLength::from_idx(byte)
119✔
134
            .map(|_| ())
119✔
135
            .map_err(|_| ZeroVecError::parse::<FieldLength>())
×
136
    }
119✔
137
}
138

139
// Safety checklist for ULE:
140
//
141
// 1. Must not include any uninitialized or padding bytes (true since transparent over a ULE).
142
// 2. Must have an alignment of 1 byte (true since transparent over a ULE).
143
// 3. ULE::validate_byte_slice() checks that the given byte slice represents a valid slice.
144
// 4. ULE::validate_byte_slice() checks that the given byte slice has a valid length
145
//    (true since transparent over a type of size 1).
146
// 5. All other methods must be left with their default impl.
147
// 6. Byte equality is semantic equality.
148
unsafe impl ULE for FieldLengthULE {
149
    fn validate_byte_slice(bytes: &[u8]) -> Result<(), ZeroVecError> {
2✔
150
        for byte in bytes {
4✔
151
            Self::validate_byte(*byte)?;
2✔
152
        }
153
        Ok(())
2✔
154
    }
2✔
155
}
156

157
/// Various numeric overrides for datetime patterns
158
/// as found in CLDR
159
#[derive(Debug, Eq, PartialEq, Clone, Copy, Ord, PartialOrd)]
×
160
#[cfg_attr(
161
    feature = "datagen",
162
    derive(serde::Serialize, databake::Bake),
×
163
    databake(path = icu_datetime::fields),
164
)]
165
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
×
166
#[non_exhaustive]
167
pub enum FieldNumericOverrides {
×
168
    /// `hanidec`
169
    Hanidec = 0,
170
    /// `hanidays`
171
    Hanidays = 1,
172
    /// `hebr`
173
    Hebr = 2,
174
    /// `romanlow`
175
    Romanlow = 3,
176
    /// `jpnyear`
177
    Jpnyear = 4,
178
}
179

180
impl TryFrom<u8> for FieldNumericOverrides {
181
    type Error = LengthError;
182
    fn try_from(other: u8) -> Result<Self, LengthError> {
×
183
        Ok(match other {
×
184
            0 => Self::Hanidec,
×
185
            1 => Self::Hanidays,
×
186
            2 => Self::Hebr,
×
187
            3 => Self::Romanlow,
×
188
            4 => Self::Jpnyear,
×
189
            _ => return Err(LengthError::InvalidLength),
×
190
        })
191
    }
×
192
}
193

194
impl FieldNumericOverrides {
195
    /// Conver this to the corresponding string code
196
    pub fn as_str(self) -> &'static str {
×
197
        match self {
×
198
            Self::Hanidec => "hanidec",
×
199
            Self::Hanidays => "hanidays",
×
200
            Self::Hebr => "hebr",
×
201
            Self::Romanlow => "romanlow",
×
202
            Self::Jpnyear => "jpnyear",
×
203
        }
204
    }
×
205
}
206

207
impl fmt::Display for FieldNumericOverrides {
208
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
×
209
        self.as_str().fmt(f)
×
210
    }
×
211
}
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