/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 | | } |