• 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

66.99
/components/locid_transform/src/fallback/mod.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
//! Tools for locale fallback, enabling arbitrary input locales to be mapped into the nearest
6
//! locale with data.
7

8
use crate::provider::*;
9
use icu_locid::extensions::unicode::Value;
10
use icu_locid::subtags::Variants;
11
use icu_provider::prelude::*;
12

13
#[doc(inline)]
14
pub use icu_provider::fallback::*;
15

16
mod algorithms;
17

18
/// Implements the algorithm defined in *[UTS #35: Locale Inheritance and Matching]*.
19
///
20
/// Note that this implementation performs some additional steps compared to the *UTS #35*
21
/// algorithm. See *[the design doc]* for a detailed description and [#2243](
22
/// https://github.com/unicode-org/icu4x/issues/2243) to track alignment with *UTS #35*.
23
///
24
/// If running fallback in a loop, use [`DataLocale::is_und()`] to break from the loop.
25
///
26
/// # Examples
27
///
28
/// ```
29
/// use icu_locid::locale;
30
/// use icu_locid_transform::fallback::LocaleFallbacker;
31
///
32
/// // Set up a LocaleFallbacker with data.
33
/// let fallbacker = LocaleFallbacker::new();
34
///
35
/// // Create a LocaleFallbackerIterator with a default configuration.
36
/// // By default, uses language priority with no additional extension keywords.
37
/// let mut fallback_iterator = fallbacker
38
///     .for_config(Default::default())
39
///     .fallback_for(locale!("hi-Latn-IN").into());
40
///
41
/// // Run the algorithm and check the results.
42
/// assert_eq!(fallback_iterator.get(), &locale!("hi-Latn-IN").into());
43
/// fallback_iterator.step();
44
/// assert_eq!(fallback_iterator.get(), &locale!("hi-Latn").into());
45
/// fallback_iterator.step();
46
/// assert_eq!(fallback_iterator.get(), &locale!("en-IN").into());
47
/// fallback_iterator.step();
48
/// assert_eq!(fallback_iterator.get(), &locale!("en-001").into());
49
/// fallback_iterator.step();
50
/// assert_eq!(fallback_iterator.get(), &locale!("en").into());
51
/// fallback_iterator.step();
52
/// assert_eq!(fallback_iterator.get(), &locale!("und").into());
53
/// ```
54
///
55
/// [UTS #35: Locale Inheritance and Matching]: https://www.unicode.org/reports/tr35/#Locale_Inheritance
56
/// [the design doc]: https://docs.google.com/document/d/1Mp7EUyl-sFh_HZYgyeVwj88vJGpCBIWxzlCwGgLCDwM/edit
57
/// [language identifier]: icu_locid::LanguageIdentifier
58
#[doc(hidden)]
59
#[derive(Debug, Clone, PartialEq)]
×
60
pub struct LocaleFallbacker {
61
    likely_subtags: DataPayload<LocaleFallbackLikelySubtagsV1Marker>,
×
62
    parents: DataPayload<LocaleFallbackParentsV1Marker>,
×
63
    collation_supplement: Option<DataPayload<CollationFallbackSupplementV1Marker>>,
×
64
}
65

66
/// Borrowed version of [`LocaleFallbacker`].
67
#[derive(Debug, Clone, Copy, PartialEq)]
×
68
pub struct LocaleFallbackerBorrowed<'a> {
69
    likely_subtags: &'a LocaleFallbackLikelySubtagsV1<'a>,
×
70
    parents: &'a LocaleFallbackParentsV1<'a>,
×
71
    collation_supplement: Option<&'a LocaleFallbackSupplementV1<'a>>,
×
72
}
73

74
/// A [`LocaleFallbackerBorrowed`] with an associated [`LocaleFallbackConfig`].
75
#[derive(Debug, Clone, Copy, PartialEq)]
×
76
pub struct LocaleFallbackerWithConfig<'a> {
77
    likely_subtags: &'a LocaleFallbackLikelySubtagsV1<'a>,
×
78
    parents: &'a LocaleFallbackParentsV1<'a>,
×
79
    supplement: Option<&'a LocaleFallbackSupplementV1<'a>>,
×
80
    config: LocaleFallbackConfig,
×
81
}
82

83
/// Inner iteration type. Does not own the item under fallback.
84
#[derive(Debug)]
×
85
struct LocaleFallbackIteratorInner<'a> {
86
    likely_subtags: &'a LocaleFallbackLikelySubtagsV1<'a>,
×
87
    parents: &'a LocaleFallbackParentsV1<'a>,
×
88
    supplement: Option<&'a LocaleFallbackSupplementV1<'a>>,
×
89
    config: LocaleFallbackConfig,
×
90
    backup_extension: Option<Value>,
×
91
    backup_subdivision: Option<Value>,
×
92
    backup_variants: Option<Variants>,
×
93
}
94

95
/// Iteration type for locale fallback operations.
96
///
97
/// Because the `Iterator` trait does not allow items to borrow from the iterator, this class does
98
/// not implement that trait. Instead, use `.step()` and `.get()`.
99
#[derive(Debug)]
×
100
pub struct LocaleFallbackIterator<'a, 'b> {
101
    current: DataLocale,
×
102
    inner: LocaleFallbackIteratorInner<'a>,
×
103
    phantom: core::marker::PhantomData<&'b ()>,
×
104
}
105

106
impl LocaleFallbacker {
107
    /// Creates a [`LocaleFallbacker`] with compiled fallback data (likely subtags and parent locales).
108
    ///
109
    /// ✨ *Enabled with the `compiled_data` Cargo feature.*
110
    ///
111
    /// [📚 Help choosing a constructor](icu_provider::constructors)
112
    #[cfg(feature = "compiled_data")]
113
    #[allow(clippy::new_ret_no_self)] // keeping constructors together
114
    pub const fn new<'a>() -> LocaleFallbackerBorrowed<'a> {
11✔
115
        let tickstatic = LocaleFallbackerBorrowed {
11✔
116
            likely_subtags: crate::provider::Baked::SINGLETON_FALLBACK_LIKELYSUBTAGS_V1,
117
            parents: crate::provider::Baked::SINGLETON_FALLBACK_PARENTS_V1,
118
            collation_supplement: Some(crate::provider::Baked::SINGLETON_FALLBACK_SUPPLEMENT_CO_V1),
11✔
119
        };
120
        // Safety: we're transmuting down from LocaleFallbackerBorrowed<'static> to LocaleFallbackerBorrowed<'a>
121
        // ZeroMaps use associated types in a way that confuse the compiler which gives up and marks them
122
        // as invariant. However, they are covariant, and in non-const code this covariance can be safely triggered
123
        // using Yokeable::transform. In const code we must transmute. In the long run we should
124
        // be able to `transform()` in const code, and also we will have hopefully improved map polymorphism (#3128)
125
        unsafe { core::mem::transmute(tickstatic) }
11✔
126
    }
11✔
127

128
    icu_provider::gen_any_buffer_data_constructors!(locale: skip, options: skip, error: DataError,
129
        #[cfg(skip)]
130
        functions: [
131
            new,
132
            try_new_with_any_provider,
133
            try_new_with_buffer_provider,
134
            try_new_unstable,
135
            Self
136
    ]);
137

138
    #[doc = icu_provider::gen_any_buffer_unstable_docs!(UNSTABLE, Self::new)]
139
    pub fn try_new_unstable<P>(provider: &P) -> Result<Self, DataError>
31✔
140
    where
141
        P: DataProvider<LocaleFallbackLikelySubtagsV1Marker>
142
            + DataProvider<LocaleFallbackParentsV1Marker>
143
            + DataProvider<CollationFallbackSupplementV1Marker>
144
            + ?Sized,
145
    {
146
        let likely_subtags = provider.load(Default::default())?.take_payload()?;
31✔
147
        let parents = provider.load(Default::default())?.take_payload()?;
31✔
148
        let collation_supplement = match DataProvider::<CollationFallbackSupplementV1Marker>::load(
31✔
149
            provider,
150
            Default::default(),
31✔
151
        ) {
152
            Ok(response) => Some(response.take_payload()?),
31✔
153
            // It is expected that not all keys are present
154
            Err(DataError {
155
                kind: DataErrorKind::MissingDataKey,
156
                ..
157
            }) => None,
×
158
            Err(e) => return Err(e),
×
159
        };
31✔
160
        Ok(LocaleFallbacker {
31✔
161
            likely_subtags,
31✔
162
            parents,
31✔
163
            collation_supplement,
31✔
164
        })
165
    }
31✔
166

167
    /// Creates a [`LocaleFallbacker`] without fallback data. Using this constructor may result in
168
    /// surprising behavior, especially in multi-script languages.
169
    pub fn new_without_data() -> Self {
11✔
170
        LocaleFallbacker {
11✔
171
            likely_subtags: DataPayload::from_owned(Default::default()),
11✔
172
            parents: DataPayload::from_owned(Default::default()),
11✔
173
            collation_supplement: None,
11✔
174
        }
×
175
    }
11✔
176

177
    /// Associates a configuration with this fallbacker.
178
    #[inline]
179
    pub fn for_config(&self, config: LocaleFallbackConfig) -> LocaleFallbackerWithConfig {
360✔
180
        self.as_borrowed().for_config(config)
360✔
181
    }
360✔
182

183
    /// Derives a configuration from a [`DataKey`] and associates it
184
    /// with this fallbacker.
185
    #[inline]
186
    #[doc(hidden)] // will be removed in 2.0
187
    pub fn for_key(&self, data_key: DataKey) -> LocaleFallbackerWithConfig {
×
188
        self.for_config(data_key.fallback_config())
×
189
    }
×
190

191
    /// Creates a borrowed version of this fallbacker for performance.
192
    pub fn as_borrowed(&self) -> LocaleFallbackerBorrowed {
362✔
193
        LocaleFallbackerBorrowed {
362✔
194
            likely_subtags: self.likely_subtags.get(),
362✔
195
            parents: self.parents.get(),
362✔
196
            collation_supplement: self.collation_supplement.as_ref().map(|p| p.get()),
713✔
197
        }
198
    }
362✔
199
}
200

201
impl<'a> LocaleFallbackerBorrowed<'a> {
202
    /// Associates a configuration with this fallbacker.
203
    #[inline]
204
    pub const fn for_config(self, config: LocaleFallbackConfig) -> LocaleFallbackerWithConfig<'a> {
410✔
205
        LocaleFallbackerWithConfig {
410✔
206
            likely_subtags: self.likely_subtags,
410✔
207
            parents: self.parents,
410✔
208
            supplement: match config.fallback_supplement {
410✔
209
                Some(LocaleFallbackSupplement::Collation) => self.collation_supplement,
54✔
210
                _ => None,
356✔
211
            },
212
            config,
410✔
213
        }
214
    }
410✔
215
}
216

217
impl LocaleFallbackerBorrowed<'static> {
218
    /// Cheaply converts a [`LocaleFallbackerBorrowed<'static>`] into a [`LocaleFallbacker`].
219
    ///
220
    /// Note: Due to branching and indirection, using [`LocaleFallbacker`] might inhibit some
221
    /// compile-time optimizations that are possible with [`LocaleFallbackerBorrowed`].
222
    pub const fn static_to_owned(self) -> LocaleFallbacker {
2✔
223
        LocaleFallbacker {
2✔
224
            likely_subtags: DataPayload::from_static_ref(self.likely_subtags),
2✔
225
            parents: DataPayload::from_static_ref(self.parents),
2✔
226
            collation_supplement: match self.collation_supplement {
2✔
227
                None => None,
×
228
                Some(x) => Some(DataPayload::from_static_ref(x)),
2✔
229
            },
UNCOV
230
        }
×
231
    }
2✔
232
}
233

234
impl<'a> LocaleFallbackerWithConfig<'a> {
235
    /// Creates an iterator based on a [`DataLocale`].
236
    ///
237
    /// If you have a [`Locale`](icu_locid::Locale), call `.into()` to get a [`DataLocale`].
238
    ///
239
    /// When first initialized, the locale is normalized according to the fallback algorithm.
240
    pub fn fallback_for(&self, mut locale: DataLocale) -> LocaleFallbackIterator<'a, 'static> {
5,672✔
241
        self.normalize(&mut locale);
5,672✔
242
        LocaleFallbackIterator {
5,672✔
243
            current: locale,
5,672✔
244
            inner: LocaleFallbackIteratorInner {
5,672✔
245
                likely_subtags: self.likely_subtags,
5,672✔
246
                parents: self.parents,
5,672✔
247
                supplement: self.supplement,
5,672✔
248
                config: self.config,
5,672✔
249
                backup_extension: None,
5,672✔
250
                backup_subdivision: None,
5,672✔
251
                backup_variants: None,
5,672✔
252
            },
253
            phantom: core::marker::PhantomData,
254
        }
255
    }
5,672✔
256
}
257

258
impl LocaleFallbackIterator<'_, '_> {
259
    /// Borrows the current [`DataLocale`] under fallback.
260
    pub fn get(&self) -> &DataLocale {
34,963✔
261
        &self.current
262
    }
34,963✔
263

264
    /// Takes the current [`DataLocale`] under fallback.
265
    pub fn take(self) -> DataLocale {
1,283✔
266
        self.current
1,283✔
267
    }
1,283✔
268

269
    /// Performs one step of the locale fallback algorithm.
270
    ///
271
    /// The fallback is completed once the inner [`DataLocale`] becomes `und`.
272
    pub fn step(&mut self) -> &mut Self {
6,208✔
273
        self.inner.step(&mut self.current);
6,208✔
274
        self
275
    }
6,208✔
276
}
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