/rust/registry/src/index.crates.io-6f17d22bba15001f/icu_plurals-1.5.0/src/provider.rs
Line | Count | Source (jump to first uncovered line) |
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 | | // Provider structs must be stable |
6 | | #![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)] |
7 | | |
8 | | //! 🚧 \[Unstable\] Data provider struct definitions for this ICU4X component. |
9 | | //! |
10 | | //! <div class="stab unstable"> |
11 | | //! 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, |
12 | | //! including in SemVer minor releases. While the serde representation of data structs is guaranteed |
13 | | //! to be stable, their Rust representation might not be. Use with caution. |
14 | | //! </div> |
15 | | //! |
16 | | //! Read more about data providers: [`icu_provider`] |
17 | | |
18 | | use crate::rules::runtime::ast::Rule; |
19 | | use icu_provider::prelude::*; |
20 | | use icu_provider::DataMarker; |
21 | | |
22 | | #[cfg(feature = "compiled_data")] |
23 | | #[derive(Debug)] |
24 | | /// Baked data |
25 | | /// |
26 | | /// <div class="stab unstable"> |
27 | | /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, |
28 | | /// including in SemVer minor releases. In particular, the `DataProvider` implementations are only |
29 | | /// guaranteed to match with this version's `*_unstable` providers. Use with caution. |
30 | | /// </div> |
31 | | pub struct Baked; |
32 | | |
33 | | #[cfg(feature = "compiled_data")] |
34 | | const _: () = { |
35 | | pub mod icu { |
36 | | pub use crate as plurals; |
37 | | #[allow(unused_imports)] // baked data may or may not need this |
38 | | pub use icu_locid_transform as locid_transform; |
39 | | } |
40 | | icu_plurals_data::make_provider!(Baked); |
41 | | icu_plurals_data::impl_plurals_ordinal_v1!(Baked); |
42 | | icu_plurals_data::impl_plurals_cardinal_v1!(Baked); |
43 | | #[cfg(feature = "experimental")] |
44 | | icu_plurals_data::impl_plurals_ranges_v1!(Baked); |
45 | | }; |
46 | | |
47 | | #[cfg(feature = "datagen")] |
48 | | /// The latest minimum set of keys required by this component. |
49 | | pub const KEYS: &[DataKey] = &[ |
50 | | CardinalV1Marker::KEY, |
51 | | OrdinalV1Marker::KEY, |
52 | | #[cfg(feature = "experimental")] |
53 | | PluralRangesV1Marker::KEY, |
54 | | ]; |
55 | | |
56 | | /// Plural rule strings conforming to UTS 35 syntax. Includes separate fields for five of the six |
57 | | /// standard plural forms. If none of the rules match, the "other" category is assumed. |
58 | | /// |
59 | | /// More information: <https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules> |
60 | | /// |
61 | | /// <div class="stab unstable"> |
62 | | /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, |
63 | | /// including in SemVer minor releases. While the serde representation of data structs is guaranteed |
64 | | /// to be stable, their Rust representation might not be. Use with caution. |
65 | | /// </div> |
66 | 0 | #[icu_provider::data_struct( |
67 | 0 | CardinalV1Marker = "plurals/cardinal@1", |
68 | 0 | OrdinalV1Marker = "plurals/ordinal@1" |
69 | 0 | )] Unexecuted instantiation: <icu_plurals::provider::PluralRulesV1 as yoke::yokeable::Yokeable>::transform Unexecuted instantiation: <icu_plurals::provider::PluralRulesV1 as zerofrom::zero_from::ZeroFrom<icu_plurals::provider::PluralRulesV1>>::zero_from Unexecuted instantiation: <icu_plurals::provider::PluralRulesV1 as yoke::yokeable::Yokeable>::transform_owned Unexecuted instantiation: <icu_plurals::provider::PluralRulesV1 as yoke::yokeable::Yokeable>::transform_mut::<_> Unexecuted instantiation: <icu_plurals::provider::PluralRulesV1 as yoke::yokeable::Yokeable>::make Unexecuted instantiation: <icu_plurals::provider::PluralRulesV1 as yoke::yokeable::Yokeable>::make |
70 | | #[derive(Default, Clone, PartialEq, Debug)] |
71 | | #[cfg_attr( |
72 | | feature = "datagen", |
73 | | derive(serde::Serialize, databake::Bake), |
74 | | databake(path = icu_plurals::provider), |
75 | | )] |
76 | | #[cfg_attr(feature = "serde", derive(serde::Deserialize))] |
77 | | pub struct PluralRulesV1<'data> { |
78 | | /// Rule that matches [`PluralCategory::Zero`](super::PluralCategory::Zero), or `None` if not present. |
79 | | #[cfg_attr(feature = "serde", serde(borrow))] |
80 | | pub zero: Option<Rule<'data>>, |
81 | | /// Rule that matches [`PluralCategory::One`](super::PluralCategory::One), or `None` if not present. |
82 | | #[cfg_attr(feature = "serde", serde(borrow))] |
83 | | pub one: Option<Rule<'data>>, |
84 | | /// Rule that matches [`PluralCategory::Two`](super::PluralCategory::Two), or `None` if not present. |
85 | | #[cfg_attr(feature = "serde", serde(borrow))] |
86 | | pub two: Option<Rule<'data>>, |
87 | | /// Rule that matches [`PluralCategory::Few`](super::PluralCategory::Few), or `None` if not present. |
88 | | #[cfg_attr(feature = "serde", serde(borrow))] |
89 | | pub few: Option<Rule<'data>>, |
90 | | /// Rule that matches [`PluralCategory::Many`](super::PluralCategory::Many), or `None` if not present. |
91 | | #[cfg_attr(feature = "serde", serde(borrow))] |
92 | | pub many: Option<Rule<'data>>, |
93 | | } |
94 | | |
95 | | pub(crate) struct ErasedPluralRulesV1Marker; |
96 | | |
97 | | impl DataMarker for ErasedPluralRulesV1Marker { |
98 | | type Yokeable = PluralRulesV1<'static>; |
99 | | } |
100 | | |
101 | | #[cfg(any(feature = "datagen", feature = "experimental"))] |
102 | | pub use ranges::*; |
103 | | |
104 | | #[cfg(any(feature = "datagen", feature = "experimental"))] |
105 | | mod ranges { |
106 | | use crate::PluralCategory; |
107 | | use icu_provider::prelude::*; |
108 | | use zerovec::ZeroMap; |
109 | | |
110 | | /// [`PluralCategory`] but serializable as provider data. |
111 | | /// |
112 | | /// <div class="stab unstable"> |
113 | | /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, |
114 | | /// including in SemVer minor releases. While the serde representation of data structs is guaranteed |
115 | | /// to be stable, their Rust representation might not be. Use with caution. |
116 | | /// </div> |
117 | | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)] |
118 | | #[cfg_attr( |
119 | | feature = "datagen", |
120 | | derive(serde::Serialize, databake::Bake), |
121 | | databake(path = icu_plurals::provider), |
122 | | )] |
123 | | #[cfg_attr(feature = "serde", derive(serde::Deserialize))] |
124 | | #[zerovec::make_ule(RawPluralCategoryULE)] |
125 | | #[repr(u8)] |
126 | | #[cfg_attr( |
127 | | any(feature = "datagen", feature = "serde"), |
128 | | serde(rename_all = "lowercase") |
129 | | )] |
130 | | pub enum RawPluralCategory { |
131 | | /// CLDR "other" plural category. |
132 | | Other = 0, |
133 | | /// CLDR "zero" plural category. |
134 | | Zero = 1, |
135 | | /// CLDR "one" plural category. |
136 | | One = 2, |
137 | | /// CLDR "two" plural category. |
138 | | Two = 3, |
139 | | /// CLDR "few" plural category. |
140 | | Few = 4, |
141 | | /// CLDR "many" plural category. |
142 | | Many = 5, |
143 | | } |
144 | | |
145 | | impl RawPluralCategory { |
146 | | /// Gets the corresponding variant string of this `RawPluralCategory`. |
147 | | #[cfg(any(feature = "datagen", feature = "serde"))] |
148 | | const fn as_str(self) -> &'static str { |
149 | | match self { |
150 | | Self::Other => "other", |
151 | | Self::Zero => "zero", |
152 | | Self::One => "one", |
153 | | Self::Two => "two", |
154 | | Self::Few => "few", |
155 | | Self::Many => "many", |
156 | | } |
157 | | } |
158 | | } |
159 | | |
160 | | impl From<RawPluralCategory> for PluralCategory { |
161 | | fn from(value: RawPluralCategory) -> Self { |
162 | | match value { |
163 | | RawPluralCategory::Other => PluralCategory::Other, |
164 | | RawPluralCategory::Zero => PluralCategory::Zero, |
165 | | RawPluralCategory::One => PluralCategory::One, |
166 | | RawPluralCategory::Two => PluralCategory::Two, |
167 | | RawPluralCategory::Few => PluralCategory::Few, |
168 | | RawPluralCategory::Many => PluralCategory::Many, |
169 | | } |
170 | | } |
171 | | } |
172 | | |
173 | | impl From<PluralCategory> for RawPluralCategory { |
174 | | fn from(value: PluralCategory) -> Self { |
175 | | match value { |
176 | | PluralCategory::Zero => RawPluralCategory::Zero, |
177 | | PluralCategory::One => RawPluralCategory::One, |
178 | | PluralCategory::Two => RawPluralCategory::Two, |
179 | | PluralCategory::Few => RawPluralCategory::Few, |
180 | | PluralCategory::Many => RawPluralCategory::Many, |
181 | | PluralCategory::Other => RawPluralCategory::Other, |
182 | | } |
183 | | } |
184 | | } |
185 | | |
186 | | /// An `u8` that is expected to be a plural range, but does not enforce this invariant. |
187 | | /// |
188 | | /// <div class="stab unstable"> |
189 | | /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, |
190 | | /// including in SemVer minor releases. While the serde representation of data structs is guaranteed |
191 | | /// to be stable, their Rust representation might not be. Use with caution. |
192 | | /// </div> |
193 | | #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Ord, PartialOrd)] |
194 | | #[cfg_attr( |
195 | | feature = "datagen", |
196 | | derive(databake::Bake), |
197 | | databake(path = icu_plurals::provider), |
198 | | )] |
199 | | #[zerovec::make_ule(UnvalidatedPluralRangeULE)] |
200 | | pub struct UnvalidatedPluralRange(pub u8); |
201 | | |
202 | | impl UnvalidatedPluralRange { |
203 | | /// Creates a new `UnvalidatedPluralRange` from a category range. |
204 | | pub fn from_range(start: RawPluralCategory, end: RawPluralCategory) -> Self { |
205 | | let start = start as u8; |
206 | | let end = end as u8; |
207 | | |
208 | | debug_assert!(start < 16); |
209 | | debug_assert!(end < 16); |
210 | | |
211 | | let range = (start << 4) | end; |
212 | | |
213 | | Self(range) |
214 | | } |
215 | | } |
216 | | |
217 | | #[cfg(feature = "datagen")] |
218 | | impl serde::Serialize for UnvalidatedPluralRange { |
219 | | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
220 | | where |
221 | | S: serde::Serializer, |
222 | | { |
223 | | use serde::ser::Error; |
224 | | |
225 | | struct PrettyPrinter(RawPluralCategory, RawPluralCategory); |
226 | | |
227 | | impl core::fmt::Display for PrettyPrinter { |
228 | | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
229 | | f.write_str(self.0.as_str())?; |
230 | | f.write_str("--")?; |
231 | | f.write_str(self.1.as_str()) |
232 | | } |
233 | | } |
234 | | |
235 | | if serializer.is_human_readable() { |
236 | | let start = RawPluralCategory::new_from_u8(self.0 >> 4) |
237 | | .ok_or_else(|| S::Error::custom("invalid tag in UnvalidatedPluralRange"))?; |
238 | | let end = RawPluralCategory::new_from_u8(self.0 & 0x0F) |
239 | | .ok_or_else(|| S::Error::custom("invalid tag in UnvalidatedPluralRange"))?; |
240 | | serializer.collect_str(&PrettyPrinter(start, end)) |
241 | | } else { |
242 | | self.0.serialize(serializer) |
243 | | } |
244 | | } |
245 | | } |
246 | | |
247 | | #[cfg(feature = "serde")] |
248 | | impl<'de> serde::Deserialize<'de> for UnvalidatedPluralRange { |
249 | | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
250 | | where |
251 | | D: serde::Deserializer<'de>, |
252 | | { |
253 | | use serde::de::{Error, Visitor}; |
254 | | |
255 | | struct HumanReadableVisitor; |
256 | | |
257 | | impl<'de> Visitor<'de> for HumanReadableVisitor { |
258 | | type Value = UnvalidatedPluralRange; |
259 | | |
260 | | fn expecting(&self, formatter: &mut alloc::fmt::Formatter) -> alloc::fmt::Result { |
261 | | write!( |
262 | | formatter, |
263 | | "a plural range of the form <PluralCategory>-<PluralCategory>", |
264 | | ) |
265 | | } |
266 | | |
267 | | fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> |
268 | | where |
269 | | E: Error, |
270 | | { |
271 | | const VARIANTS: [&str; 6] = [ |
272 | | RawPluralCategory::Other.as_str(), |
273 | | RawPluralCategory::Zero.as_str(), |
274 | | RawPluralCategory::One.as_str(), |
275 | | RawPluralCategory::Two.as_str(), |
276 | | RawPluralCategory::Few.as_str(), |
277 | | RawPluralCategory::Many.as_str(), |
278 | | ]; |
279 | | |
280 | | let (start, end) = v |
281 | | .split_once("--") |
282 | | .ok_or_else(|| E::custom("expected token `--` in plural range"))?; |
283 | | |
284 | | let start = PluralCategory::get_for_cldr_string(start) |
285 | | .ok_or_else(|| E::unknown_variant(start, &VARIANTS))?; |
286 | | let end = PluralCategory::get_for_cldr_string(end) |
287 | | .ok_or_else(|| E::unknown_variant(end, &VARIANTS))?; |
288 | | |
289 | | Ok(UnvalidatedPluralRange::from_range(start.into(), end.into())) |
290 | | } |
291 | | } |
292 | | |
293 | | if deserializer.is_human_readable() { |
294 | | deserializer.deserialize_str(HumanReadableVisitor) |
295 | | } else { |
296 | | Ok(Self(<u8>::deserialize(deserializer)?)) |
297 | | } |
298 | | } |
299 | | } |
300 | | |
301 | | /// Plural categories for ranges. |
302 | | /// |
303 | | /// Obtains the plural category of a range from the categories of its endpoints. It is required that |
304 | | /// the start value must be strictly less than the end value, and both values must be strictly positive. |
305 | | /// |
306 | | /// More information: <https://unicode.org/reports/tr35/tr35-numbers.html#Plural_Ranges> |
307 | | /// |
308 | | /// <div class="stab unstable"> |
309 | | /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, |
310 | | /// including in SemVer minor releases. While the serde representation of data structs is guaranteed |
311 | | /// to be stable, their Rust representation might not be. Use with caution. |
312 | | /// </div> |
313 | | #[icu_provider::data_struct(PluralRangesV1Marker = "plurals/ranges@1")] |
314 | | #[derive(Clone, PartialEq, Debug)] |
315 | | #[cfg_attr( |
316 | | feature = "datagen", |
317 | | derive(serde::Serialize, databake::Bake), |
318 | | databake(path = icu_plurals::provider), |
319 | | )] |
320 | | #[cfg_attr(feature = "serde", derive(serde::Deserialize))] |
321 | | #[yoke(prove_covariance_manually)] |
322 | | pub struct PluralRangesV1<'data> { |
323 | | /// Map between the categories of the endpoints of a range and its corresponding |
324 | | /// category. |
325 | | /// |
326 | | /// This is roughly equivalent to a `BTreeMap<(PluralCategory, PluralCategory), PluralCategory>`, |
327 | | /// where the key is `(start category, end category)`. |
328 | | #[cfg_attr(feature = "serde", serde(borrow))] |
329 | | pub ranges: ZeroMap<'data, UnvalidatedPluralRange, RawPluralCategory>, |
330 | | } |
331 | | } |