Coverage Report

Created: 2025-09-27 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/icu_capi-1.5.1/src/provider.rs
Line
Count
Source
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
#[allow(unused_imports)] // feature-specific
6
use alloc::boxed::Box;
7
use icu_provider::prelude::*;
8
#[allow(unused_imports)] // feature-specific
9
use icu_provider::MaybeSendSync;
10
use icu_provider_adapters::empty::EmptyDataProvider;
11
#[allow(unused_imports)] // feature-specific
12
use yoke::{trait_hack::YokeTraitHack, Yokeable};
13
#[allow(unused_imports)] // feature-specific
14
use zerofrom::ZeroFrom;
15
16
pub enum ICU4XDataProviderInner {
17
    Destroyed,
18
    Empty,
19
    #[cfg(feature = "compiled_data")]
20
    Compiled,
21
    #[cfg(feature = "buffer_provider")]
22
    Buffer(Box<dyn BufferProvider + 'static>),
23
}
24
25
#[diplomat::bridge]
26
pub mod ffi {
27
    use super::ICU4XDataProviderInner;
28
    use crate::errors::ffi::ICU4XError;
29
    use alloc::boxed::Box;
30
    #[allow(unused_imports)] // feature-gated
31
    use icu_provider_adapters::fallback::LocaleFallbackProvider;
32
    #[allow(unused_imports)] // feature-gated
33
    use icu_provider_adapters::fork::predicates::MissingLocalePredicate;
34
35
    #[diplomat::opaque]
36
    /// An ICU4X data provider, capable of loading ICU4X data keys from some source.
37
    #[diplomat::rust_link(icu_provider, Mod)]
38
    pub struct ICU4XDataProvider(pub ICU4XDataProviderInner);
39
40
    #[cfg(feature = "buffer_provider")]
41
    fn convert_buffer_provider<D: icu_provider::BufferProvider + 'static>(
42
        x: D,
43
    ) -> ICU4XDataProvider {
44
        ICU4XDataProvider(super::ICU4XDataProviderInner::Buffer(Box::new(x)))
45
    }
46
47
    impl ICU4XDataProvider {
48
        /// Constructs an [`ICU4XDataProvider`] that uses compiled data.
49
        ///
50
        /// Requires the `compiled_data` feature.
51
        ///
52
        /// This provider cannot be modified or combined with other providers, so `enable_fallback`,
53
        /// `enabled_fallback_with`, `fork_by_locale`, and `fork_by_key` will return `Err`s.
54
        #[cfg(feature = "compiled_data")]
55
        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "compiled")]
56
0
        pub fn create_compiled() -> Box<ICU4XDataProvider> {
57
0
            Box::new(Self(ICU4XDataProviderInner::Compiled))
58
0
        }
59
60
        /// Constructs an `FsDataProvider` and returns it as an [`ICU4XDataProvider`].
61
        /// Requires the `provider_fs` Cargo feature.
62
        /// Not supported in WASM.
63
        #[diplomat::rust_link(icu_provider_fs::FsDataProvider, Struct)]
64
        #[cfg(all(
65
            feature = "provider_fs",
66
            not(any(target_arch = "wasm32", target_os = "none"))
67
        ))]
68
        #[diplomat::attr(dart, disable)]
69
        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "fs")]
70
        pub fn create_fs(path: &DiplomatStr) -> Result<Box<ICU4XDataProvider>, ICU4XError> {
71
            Ok(Box::new(convert_buffer_provider(
72
                icu_provider_fs::FsDataProvider::try_new(
73
                    // In the future we can start using OsString APIs to support non-utf8 paths
74
                    core::str::from_utf8(path)
75
                        .map_err(|e| ICU4XError::DataIoError.log_original(&e))?,
76
                )?,
77
            )))
78
        }
79
80
        /// Deprecated
81
        ///
82
        /// Use `create_compiled()`.
83
        #[cfg(all(
84
            feature = "provider_test",
85
            any(feature = "any_provider", feature = "buffer_provider")
86
        ))]
87
        #[diplomat::attr(supports = constructors, disable)]
88
        pub fn create_test() -> Box<ICU4XDataProvider> {
89
            Self::create_compiled()
90
        }
91
92
        /// Constructs a `BlobDataProvider` and returns it as an [`ICU4XDataProvider`].
93
        #[diplomat::rust_link(icu_provider_blob::BlobDataProvider, Struct)]
94
        #[cfg(feature = "buffer_provider")]
95
        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "from_byte_slice")]
96
        pub fn create_from_byte_slice(
97
            blob: &'static [DiplomatByte],
98
        ) -> Result<Box<ICU4XDataProvider>, ICU4XError> {
99
            Ok(Box::new(convert_buffer_provider(
100
                icu_provider_blob::BlobDataProvider::try_new_from_static_blob(blob)?,
101
            )))
102
        }
103
104
        /// Constructs an empty [`ICU4XDataProvider`].
105
        #[diplomat::rust_link(icu_provider_adapters::empty::EmptyDataProvider, Struct)]
106
        #[diplomat::rust_link(
107
            icu_provider_adapters::empty::EmptyDataProvider::new,
108
            FnInStruct,
109
            hidden
110
        )]
111
        #[diplomat::attr(all(supports = constructors, supports = fallible_constructors, supports = named_constructors), named_constructor = "empty")]
112
0
        pub fn create_empty() -> Box<ICU4XDataProvider> {
113
0
            Box::new(ICU4XDataProvider(ICU4XDataProviderInner::Empty))
114
0
        }
115
116
        /// Creates a provider that tries the current provider and then, if the current provider
117
        /// doesn't support the data key, another provider `other`.
118
        ///
119
        /// This takes ownership of the `other` provider, leaving an empty provider in its place.
120
        ///
121
        /// The providers must be the same type (Any or Buffer). This condition is satisfied if
122
        /// both providers originate from the same constructor, such as `create_from_byte_slice`
123
        /// or `create_fs`. If the condition is not upheld, a runtime error occurs.
124
        #[diplomat::rust_link(icu_provider_adapters::fork::ForkByKeyProvider, Typedef)]
125
        #[diplomat::rust_link(
126
            icu_provider_adapters::fork::predicates::MissingDataKeyPredicate,
127
            Struct,
128
            hidden
129
        )]
130
0
        pub fn fork_by_key(&mut self, other: &mut ICU4XDataProvider) -> Result<(), ICU4XError> {
131
            #[allow(unused_imports)]
132
            use ICU4XDataProviderInner::*;
133
            *self = match (
134
0
                core::mem::replace(&mut self.0, Destroyed),
135
0
                core::mem::replace(&mut other.0, Destroyed),
136
            ) {
137
0
                (Destroyed, _) | (_, Destroyed) => Err(icu_provider::DataError::custom(
138
0
                    "This provider has been destroyed",
139
0
                ))?,
140
                #[cfg(feature = "compiled_data")]
141
0
                (Compiled, _) | (_, Compiled) => Err(icu_provider::DataError::custom(
142
0
                    "The compiled provider cannot be modified",
143
0
                ))?,
144
0
                (Empty, Empty) => ICU4XDataProvider(ICU4XDataProviderInner::Empty),
145
                #[cfg(feature = "buffer_provider")]
146
                (Empty, b) | (b, Empty) => ICU4XDataProvider(b),
147
                #[cfg(feature = "buffer_provider")]
148
                (Buffer(a), Buffer(b)) => convert_buffer_provider(
149
                    icu_provider_adapters::fork::ForkByKeyProvider::new(a, b),
150
                ),
151
            };
152
0
            Ok(())
153
0
        }
154
155
        /// Same as `fork_by_key` but forks by locale instead of key.
156
        #[diplomat::rust_link(
157
            icu_provider_adapters::fork::predicates::MissingLocalePredicate,
158
            Struct
159
        )]
160
0
        pub fn fork_by_locale(&mut self, other: &mut ICU4XDataProvider) -> Result<(), ICU4XError> {
161
            #[allow(unused_imports)]
162
            use ICU4XDataProviderInner::*;
163
            *self = match (
164
0
                core::mem::replace(&mut self.0, Destroyed),
165
0
                core::mem::replace(&mut other.0, Destroyed),
166
            ) {
167
0
                (Destroyed, _) | (_, Destroyed) => Err(icu_provider::DataError::custom(
168
0
                    "This provider has been destroyed",
169
0
                ))?,
170
                #[cfg(feature = "compiled_data")]
171
0
                (Compiled, _) | (_, Compiled) => Err(icu_provider::DataError::custom(
172
0
                    "The compiled provider cannot be modified",
173
0
                ))?,
174
0
                (Empty, Empty) => ICU4XDataProvider(ICU4XDataProviderInner::Empty),
175
                #[cfg(feature = "buffer_provider")]
176
                (Empty, b) | (b, Empty) => ICU4XDataProvider(b),
177
                #[cfg(feature = "buffer_provider")]
178
                (Buffer(a), Buffer(b)) => convert_buffer_provider(
179
                    icu_provider_adapters::fork::ForkByErrorProvider::new_with_predicate(
180
                        a,
181
                        b,
182
                        MissingLocalePredicate,
183
                    ),
184
                ),
185
            };
186
0
            Ok(())
187
0
        }
188
189
        /// Enables locale fallbacking for data requests made to this provider.
190
        ///
191
        /// Note that the test provider (from `create_test`) already has fallbacking enabled.
192
        #[diplomat::rust_link(
193
            icu_provider_adapters::fallback::LocaleFallbackProvider::try_new,
194
            FnInStruct
195
        )]
196
        #[diplomat::rust_link(
197
            icu_provider_adapters::fallback::LocaleFallbackProvider,
198
            Struct,
199
            compact
200
        )]
201
0
        pub fn enable_locale_fallback(&mut self) -> Result<(), ICU4XError> {
202
            use ICU4XDataProviderInner::*;
203
0
            *self = match core::mem::replace(&mut self.0, Destroyed) {
204
0
                Destroyed => Err(icu_provider::DataError::custom(
205
0
                    "This provider has been destroyed",
206
0
                ))?,
207
                #[cfg(feature = "compiled_data")]
208
0
                Compiled => Err(icu_provider::DataError::custom(
209
0
                    "The compiled provider cannot be modified",
210
0
                ))?,
211
0
                Empty => Err(icu_provider::DataErrorKind::MissingDataKey.into_error())?,
212
                #[cfg(feature = "buffer_provider")]
213
                Buffer(inner) => convert_buffer_provider(
214
                    LocaleFallbackProvider::try_new_with_buffer_provider(inner)?,
215
                ),
216
            };
217
0
            Ok(())
218
0
        }
219
220
        #[diplomat::rust_link(
221
            icu_provider_adapters::fallback::LocaleFallbackProvider::new_with_fallbacker,
222
            FnInStruct
223
        )]
224
        #[diplomat::rust_link(
225
            icu_provider_adapters::fallback::LocaleFallbackProvider,
226
            Struct,
227
            compact
228
        )]
229
        #[allow(unused_variables)] // feature-gated
230
        #[cfg(feature = "icu_locid_transform")]
231
0
        pub fn enable_locale_fallback_with(
232
0
            &mut self,
233
0
            fallbacker: &crate::fallbacker::ffi::ICU4XLocaleFallbacker,
234
0
        ) -> Result<(), ICU4XError> {
235
            use ICU4XDataProviderInner::*;
236
0
            *self = match core::mem::replace(&mut self.0, Destroyed) {
237
0
                Destroyed => Err(icu_provider::DataError::custom(
238
0
                    "This provider has been destroyed",
239
0
                ))?,
240
                #[cfg(feature = "compiled_data")]
241
0
                Compiled => Err(icu_provider::DataError::custom(
242
0
                    "The compiled provider cannot be modified",
243
0
                ))?,
244
0
                Empty => Err(icu_provider::DataErrorKind::MissingDataKey.into_error())?,
245
                #[cfg(feature = "buffer_provider")]
246
                Buffer(inner) => convert_buffer_provider(
247
                    LocaleFallbackProvider::new_with_fallbacker(inner, fallbacker.0.clone()),
248
                ),
249
            };
250
0
            Ok(())
251
0
        }
252
    }
253
}
254
255
macro_rules! load {
256
    () => {
257
0
        fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
258
            use ICU4XDataProviderInner::*;
259
0
            match self {
260
0
                Destroyed => Err(icu_provider::DataError::custom(
261
0
                    "This provider has been destroyed",
262
0
                ))?,
263
0
                Empty => EmptyDataProvider::new().load(req),
264
                #[cfg(feature = "buffer_provider")]
265
                Buffer(buffer_provider) => buffer_provider.as_deserializing().load(req),
266
                #[cfg(feature = "compiled_data")]
267
0
                Compiled => unreachable!(),
268
            }
269
0
        }
270
    };
271
}
272
273
#[macro_export]
274
macro_rules! call_constructor {
275
    ($compiled:path [$pre_transform:ident => $transform:expr], $any:path, $buffer:path, $provider:expr $(, $args:expr)* $(,)?) => {
276
        match &$provider.0 {
277
            $crate::provider::ICU4XDataProviderInner::Destroyed => Err(icu_provider::DataError::custom(
278
                "This provider has been destroyed",
279
            ))?,
280
            $crate::provider::ICU4XDataProviderInner::Empty => $any(&icu_provider_adapters::empty::EmptyDataProvider::new(), $($args,)*),
281
            #[cfg(feature = "buffer_provider")]
282
            $crate::provider::ICU4XDataProviderInner::Buffer(buffer_provider) => $buffer(buffer_provider, $($args,)*),
283
            #[cfg(feature = "compiled_data")]
284
            $crate::provider::ICU4XDataProviderInner::Compiled => { let $pre_transform = $compiled($($args,)*); $transform },
285
        }
286
    };
287
    ($compiled:path, $any:path, $buffer:path, $provider:expr $(, $args:expr)* $(,)?) => {
288
        match &$provider.0 {
289
            $crate::provider::ICU4XDataProviderInner::Destroyed => Err(icu_provider::DataError::custom(
290
                "This provider has been destroyed",
291
            ))?,
292
            $crate::provider::ICU4XDataProviderInner::Empty => $any(&icu_provider_adapters::empty::EmptyDataProvider::new(), $($args,)*),
293
            #[cfg(feature = "buffer_provider")]
294
            $crate::provider::ICU4XDataProviderInner::Buffer(buffer_provider) => $buffer(buffer_provider, $($args,)*),
295
            #[cfg(feature = "compiled_data")]
296
            $crate::provider::ICU4XDataProviderInner::Compiled => $compiled($($args,)*),
297
        }
298
    };
299
}
300
301
#[macro_export]
302
macro_rules! call_constructor_unstable {
303
    ($compiled:path [$pre_transform:ident => $transform:expr], $unstable:path, $provider:expr $(, $args:expr)* $(,)?) => {
304
        match &$provider.0 {
305
            $crate::provider::ICU4XDataProviderInner::Destroyed => Err(icu_provider::DataError::custom(
306
                "This provider has been destroyed",
307
            ))?,
308
            $crate::provider::ICU4XDataProviderInner::Empty => $unstable(&icu_provider_adapters::empty::EmptyDataProvider::new(), $($args,)*),
309
            #[cfg(feature = "buffer_provider")]
310
            $crate::provider::ICU4XDataProviderInner::Buffer(buffer_provider) => $unstable(&icu_provider::AsDeserializingBufferProvider::as_deserializing(buffer_provider), $($args,)*),
311
            #[cfg(feature = "compiled_data")]
312
            $crate::provider::ICU4XDataProviderInner::Compiled => { let $pre_transform = $compiled($($args,)*); $transform },
313
        }
314
    };
315
    ($compiled:path, $unstable:path, $provider:expr $(, $args:expr)* $(,)?) => {
316
        match &$provider.0 {
317
            $crate::provider::ICU4XDataProviderInner::Destroyed => Err(icu_provider::DataError::custom(
318
                "This provider has been destroyed",
319
            ))?,
320
            $crate::provider::ICU4XDataProviderInner::Empty => $unstable(&icu_provider_adapters::empty::EmptyDataProvider::new(), $($args,)*),
321
            #[cfg(feature = "buffer_provider")]
322
            $crate::provider::ICU4XDataProviderInner::Buffer(buffer_provider) => $unstable(&icu_provider::AsDeserializingBufferProvider::as_deserializing(buffer_provider), $($args,)*),
323
            #[cfg(feature = "compiled_data")]
324
            $crate::provider::ICU4XDataProviderInner::Compiled => $compiled($($args,)*),
325
        }
326
    };
327
}
328
329
#[cfg(not(feature = "buffer_provider"))]
330
impl<M> DataProvider<M> for ICU4XDataProviderInner
331
where
332
    M: KeyedDataMarker,
333
{
334
    load!();
335
}
336
337
#[cfg(feature = "buffer_provider")]
338
impl<M> DataProvider<M> for ICU4XDataProviderInner
339
where
340
    M: KeyedDataMarker,
341
    // Actual bound:
342
    //     for<'de> <M::Yokeable as Yokeable<'de>>::Output: Deserialize<'de>,
343
    // Necessary workaround bound (see `yoke::trait_hack` docs):
344
    for<'de> YokeTraitHack<<M::Yokeable as Yokeable<'de>>::Output>: serde::Deserialize<'de>,
345
{
346
    load!();
347
}