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 | //! 📚 *This module documents ICU4X constructor signatures.* |
6 | //! |
7 | //! One of the key differences between ICU4X and its parent projects, ICU4C and ICU4J, is in how |
8 | //! it deals with locale data. |
9 | //! |
10 | //! In ICU4X, data can always be explicitly passed to any function that requires data. |
11 | //! This enables ICU4X to achieve the following value propositions: |
12 | //! |
13 | //! 1. Configurable data sources (machine-readable data file, baked into code, JSON, etc). |
14 | //! 2. Dynamic data loading at runtime (load data on demand). |
15 | //! 3. Reduced overhead and code size (data is resolved locally at each call site). |
16 | //! 4. Explicit support for multiple ICU4X instances sharing data. |
17 | //! |
18 | //! However, as manual data management can be tedious, ICU4X also has a `compiled_data` |
19 | //! default Cargo feature that includes data and makes ICU4X work out-of-the box. |
20 | //! |
21 | //! Subsequently, there are 4 versions of all Rust ICU4X functions that use data: |
22 | //! |
23 | //! 1. `*` |
24 | //! 2. `*_unstable` |
25 | //! 3. `*_with_any_provider` |
26 | //! 4. `*_with_buffer_provider` |
27 | //! |
28 | //! # Which constructor should I use? |
29 | //! |
30 | //! ## When to use `*` |
31 | //! |
32 | //! If you don't want to customize data at runtime (i.e. if you don't care about code size, |
33 | //! updating your data, etc.) you can use the `compiled_data` Cargo feature and don't have to think |
34 | //! about where your data comes from. |
35 | //! |
36 | //! These constructors are sometimes `const` functions, this way Rust can most effectively optimize |
37 | //! your usage of ICU4X. |
38 | //! |
39 | //! ## When to use `*_unstable` |
40 | //! |
41 | //! Use this constructor if your data provider implements the [`DataProvider`] trait for all |
42 | //! data structs in *current and future* ICU4X versions. Examples: |
43 | //! |
44 | //! 1. `BakedDataProvider` generated for the specific ICU4X minor version |
45 | //! 2. Anything with a _blanket_ [`DataProvider`] impl |
46 | //! |
47 | //! Since the exact set of bounds may change at any time, including in minor SemVer releases, |
48 | //! it is the client's responsibility to guarantee that the requirement is upheld. |
49 | //! |
50 | //! ## When to use `*_with_any_provider` |
51 | //! |
52 | //! Use this constructor if you need to use a provider that implements [`AnyProvider`] but not |
53 | //! [`DataProvider`]. Examples: |
54 | //! |
55 | //! 1. [`AnyPayloadProvider`] |
56 | //! 2. [`ForkByKeyProvider`] between two providers implementing [`AnyProvider`] |
57 | //! 3. Providers that cache or override certain keys but not others and therefore |
58 | //! can't implement [`DataProvider`] |
59 | //! |
60 | //! ## When to use `*_with_buffer_provider` |
61 | //! |
62 | //! Use this constructor if your data originates as byte buffers that need to be deserialized. |
63 | //! All such providers should implement [`BufferProvider`]. Examples: |
64 | //! |
65 | //! 1. [`BlobDataProvider`] |
66 | //! 2. [`FsDataProvider`] |
67 | //! 3. [`ForkByKeyProvider`] between two providers implementing [`BufferProvider`] |
68 | //! |
69 | //! Please note that you must enable the `serde` Cargo feature on each crate in which you use the |
70 | //! `*_with_buffer_provider` constructor. |
71 | //! |
72 | //! # Data Versioning Policy |
73 | //! |
74 | //! The `*_with_any_provider` and `*_with_buffer_provider` functions will succeed to compile and |
75 | //! run if given a data provider supporting all of the keys required for the object being |
76 | //! constructed, either the current or any previous version within the same SemVer major release. |
77 | //! For example, if a data file is built to support FooFormatter version 1.1, then FooFormatter |
78 | //! version 1.2 will be able to read the same data file. Likewise, backwards-compatible keys can |
79 | //! always be included by `icu_datagen` to support older library versions. |
80 | //! |
81 | //! The `*_unstable` functions are only guaranteed to work on data built for the exact same minor version |
82 | //! of ICU4X. The advantage of the `*_unstable` functions is that they result in the smallest code |
83 | //! size and allow for automatic data slicing when `BakedDataProvider` is used. However, the type |
84 | //! bounds of this function may change over time, breaking SemVer guarantees. These functions |
85 | //! should therefore only be used when you have full control over your data lifecycle at compile |
86 | //! time. |
87 | //! |
88 | //! # Data Providers Over FFI |
89 | //! |
90 | //! Over FFI, there is only one data provider type: [`ICU4XDataProvider`]. Internally, it is an |
91 | //! `enum` between`dyn `[`BufferProvider`] and a unit compiled data variant. |
92 | //! |
93 | //! To control for code size, there are two Cargo features, `compiled_data` and `buffer_provider`, |
94 | //! that enable the corresponding items in the enum. |
95 | //! |
96 | //! In Rust ICU4X, a similar enum approach was not taken because: |
97 | //! |
98 | //! 1. Feature-gating the enum branches gets complex across crates. |
99 | //! 2. Without feature gating, users need to carry Serde code even if they're not using it, |
100 | //! violating one of the core value propositions of ICU4X. |
101 | //! 3. We could reduce the number of constructors from 4 to 2 but not to 1, so the educational |
102 | //! benefit is limited. |
103 | //! |
104 | //! [`DataProvider`]: crate::DataProvider |
105 | //! [`BufferProvider`]: crate::BufferProvider |
106 | //! [`AnyProvider`]: crate::AnyProvider |
107 | //! [`AnyPayloadProvider`]: ../../icu_provider_adapters/any_payload/struct.AnyPayloadProvider.html |
108 | //! [`ForkByKeyProvider`]: ../../icu_provider_adapters/fork/struct.ForkByKeyProvider.html |
109 | //! [`BlobDataProvider`]: ../../icu_provider_blob/struct.BlobDataProvider.html |
110 | //! [`StaticDataProvider`]: ../../icu_provider_blob/struct.StaticDataProvider.html |
111 | //! [`FsDataProvider`]: ../../icu_provider_blob/struct.FsDataProvider.html |
112 | //! [`ICU4XDataProvider`]: ../../icu_capi/provider/ffi/struct.ICU4XDataProvider.html |
113 | |
114 | #[doc (hidden)] |
115 | #[macro_export ] |
116 | macro_rules! gen_any_buffer_unstable_docs { |
117 | (ANY, $data:path) => { |
118 | concat!( |
119 | "A version of [`" , stringify!($data), "`] that uses custom data " , |
120 | "provided by an [`AnyProvider`](icu_provider::AnyProvider). \n\n" , |
121 | "[📚 Help choosing a constructor](icu_provider::constructors)" , |
122 | ) |
123 | }; |
124 | (BUFFER, $data:path) => { |
125 | concat!( |
126 | "A version of [`" , stringify!($data), "`] that uses custom data " , |
127 | "provided by a [`BufferProvider`](icu_provider::BufferProvider). \n\n" , |
128 | "✨ *Enabled with the `serde` feature.* \n\n" , |
129 | "[📚 Help choosing a constructor](icu_provider::constructors)" , |
130 | ) |
131 | }; |
132 | (UNSTABLE, $data:path) => { |
133 | concat!( |
134 | "A version of [`" , stringify!($data), "`] that uses custom data " , |
135 | "provided by a [`DataProvider`](icu_provider::DataProvider). \n\n" , |
136 | "[📚 Help choosing a constructor](icu_provider::constructors) \n\n" , |
137 | "<div class= \"stab unstable \">⚠️ The bounds on <tt>provider</tt> may change over time, including in SemVer minor releases.</div>" |
138 | ) |
139 | }; |
140 | } |
141 | |
142 | #[allow (clippy::crate_in_macro_def)] // by convention each crate's data provider is `crate::provider::Baked` |
143 | #[doc (hidden)] |
144 | #[macro_export ] |
145 | macro_rules! gen_any_buffer_data_constructors { |
146 | (locale: skip, options: skip, error: $error_ty:path, $(#[$doc:meta])+) => { |
147 | $crate::gen_any_buffer_data_constructors!( |
148 | locale: skip, |
149 | options: skip, |
150 | error: $error_ty, |
151 | $(#[$doc])+ |
152 | functions: [ |
153 | try_new, |
154 | try_new_with_any_provider, |
155 | try_new_with_buffer_provider, |
156 | try_new_unstable, |
157 | Self, |
158 | ] |
159 | ); |
160 | }; |
161 | (locale: skip, options: skip, error: $error_ty:path, $(#[$doc:meta])+ functions: [$baked:ident, $any:ident, $buffer:ident, $unstable:ident $(, $struct:ident)? $(,)?]) => { |
162 | #[cfg(feature = "compiled_data" )] |
163 | $(#[$doc])+ |
164 | pub fn $baked() -> Result<Self, $error_ty> { |
165 | $($struct :: )? $unstable(&crate::provider::Baked) |
166 | } |
167 | #[doc = $crate::gen_any_buffer_unstable_docs!(ANY, $($struct ::)? $baked)] |
168 | pub fn $any(provider: &(impl $crate::AnyProvider + ?Sized)) -> Result<Self, $error_ty> { |
169 | use $crate::AsDowncastingAnyProvider; |
170 | $($struct :: )? $unstable(&provider.as_downcasting()) |
171 | } |
172 | #[cfg(feature = "serde" )] |
173 | #[doc = $crate::gen_any_buffer_unstable_docs!(BUFFER, $($struct ::)? $baked)] |
174 | pub fn $buffer(provider: &(impl $crate::BufferProvider + ?Sized)) -> Result<Self, $error_ty> { |
175 | use $crate::AsDeserializingBufferProvider; |
176 | $($struct :: )? $unstable(&provider.as_deserializing()) |
177 | } |
178 | }; |
179 | |
180 | |
181 | (locale: skip, options: skip, result: $result_ty:path, $(#[$doc:meta])+ functions: [$baked:ident, $any:ident, $buffer:ident, $unstable:ident $(, $struct:ident)? $(,)?]) => { |
182 | #[cfg(feature = "compiled_data" )] |
183 | $(#[$doc])+ |
184 | pub fn $baked() -> $result_ty { |
185 | $($struct :: )? $unstable(&crate::provider::Baked) |
186 | } |
187 | #[doc = $crate::gen_any_buffer_unstable_docs!(ANY, $($struct ::)? $baked)] |
188 | pub fn $any(provider: &(impl $crate::AnyProvider + ?Sized)) -> $result_ty { |
189 | use $crate::AsDowncastingAnyProvider; |
190 | $($struct :: )? $unstable(&provider.as_downcasting()) |
191 | } |
192 | #[cfg(feature = "serde" )] |
193 | #[doc = $crate::gen_any_buffer_unstable_docs!(BUFFER, $($struct ::)? $baked)] |
194 | pub fn $buffer(provider: &(impl $crate::BufferProvider + ?Sized)) -> $result_ty { |
195 | use $crate::AsDeserializingBufferProvider; |
196 | $($struct :: )? $unstable(&provider.as_deserializing()) |
197 | } |
198 | }; |
199 | |
200 | (locale: skip, $options_arg:ident: $options_ty:ty, error: $error_ty:path, $(#[$doc:meta])+) => { |
201 | $crate::gen_any_buffer_data_constructors!( |
202 | locale: skip, |
203 | $options_arg: $options_ty, |
204 | error: $error_ty, |
205 | $(#[$doc])+ |
206 | functions: [ |
207 | try_new, |
208 | try_new_with_any_provider, |
209 | try_new_with_buffer_provider, |
210 | try_new_unstable, |
211 | Self, |
212 | ] |
213 | ); |
214 | }; |
215 | (locale: skip, $options_arg:ident: $options_ty:ty, result: $result_ty:ty, $(#[$doc:meta])+ functions: [$baked:ident, $any:ident, $buffer:ident, $unstable:ident $(, $struct:ident)? $(,)?]) => { |
216 | #[cfg(feature = "compiled_data" )] |
217 | $(#[$doc])+ |
218 | /// |
219 | /// ✨ *Enabled with the `compiled_data` Cargo feature.* |
220 | /// |
221 | /// [📚 Help choosing a constructor](icu_provider::constructors) |
222 | pub fn $baked($options_arg: $options_ty) -> $result_ty { |
223 | $($struct :: )? $unstable(&crate::provider::Baked, $options_arg) |
224 | } |
225 | #[doc = $crate::gen_any_buffer_unstable_docs!(ANY, $($struct ::)? $baked)] |
226 | pub fn $any(provider: &(impl $crate::AnyProvider + ?Sized), $options_arg: $options_ty) -> $result_ty { |
227 | use $crate::AsDowncastingAnyProvider; |
228 | $($struct :: )? $unstable(&provider.as_downcasting(), $options_arg) |
229 | } |
230 | #[cfg(feature = "serde" )] |
231 | #[doc = $crate::gen_any_buffer_unstable_docs!(BUFFER, $($struct ::)? $baked)] |
232 | pub fn $buffer(provider: &(impl $crate::BufferProvider + ?Sized), $options_arg: $options_ty) -> $result_ty { |
233 | use $crate::AsDeserializingBufferProvider; |
234 | $($struct :: )? $unstable(&provider.as_deserializing(), $options_arg) |
235 | } |
236 | }; |
237 | (locale: skip, $options_arg:ident: $options_ty:ty, error: $error_ty:ty, $(#[$doc:meta])+ functions: [$baked:ident, $any:ident, $buffer:ident, $unstable:ident $(, $struct:ident)? $(,)?]) => { |
238 | #[cfg(feature = "compiled_data" )] |
239 | $(#[$doc])+ |
240 | /// |
241 | /// ✨ *Enabled with the `compiled_data` Cargo feature.* |
242 | /// |
243 | /// [📚 Help choosing a constructor](icu_provider::constructors) |
244 | pub fn $baked($options_arg: $options_ty) -> Result<Self, $error_ty> { |
245 | $($struct :: )? $unstable(&crate::provider::Baked, $options_arg) |
246 | } |
247 | #[doc = $crate::gen_any_buffer_unstable_docs!(ANY, $($struct ::)? $baked)] |
248 | pub fn $any(provider: &(impl $crate::AnyProvider + ?Sized), $options_arg: $options_ty) -> Result<Self, $error_ty> { |
249 | use $crate::AsDowncastingAnyProvider; |
250 | $($struct :: )? $unstable(&provider.as_downcasting(), $options_arg) |
251 | } |
252 | #[cfg(feature = "serde" )] |
253 | #[doc = $crate::gen_any_buffer_unstable_docs!(BUFFER, $($struct ::)? $baked)] |
254 | pub fn $buffer(provider: &(impl $crate::BufferProvider + ?Sized), $options_arg: $options_ty) -> Result<Self, $error_ty> { |
255 | use $crate::AsDeserializingBufferProvider; |
256 | $($struct :: )? $unstable(&provider.as_deserializing(), $options_arg) |
257 | } |
258 | }; |
259 | (locale: include, options: skip, error: $error_ty:path, $(#[$doc:meta])+) => { |
260 | $crate::gen_any_buffer_data_constructors!( |
261 | locale: include, |
262 | options: skip, |
263 | error: $error_ty, |
264 | $(#[$doc])+ |
265 | functions: [ |
266 | try_new, |
267 | try_new_with_any_provider, |
268 | try_new_with_buffer_provider, |
269 | try_new_unstable, |
270 | Self, |
271 | ] |
272 | ); |
273 | }; |
274 | (locale: include, options: skip, error: $error_ty:path, $(#[$doc:meta])+ functions: [$baked:ident, $any:ident, $buffer:ident, $unstable:ident $(, $struct:ident)? $(,)?]) => { |
275 | #[cfg(feature = "compiled_data" )] |
276 | $(#[$doc])+ |
277 | /// |
278 | /// ✨ *Enabled with the `compiled_data` Cargo feature.* |
279 | /// |
280 | /// [📚 Help choosing a constructor](icu_provider::constructors) |
281 | pub fn $baked(locale: &$crate::DataLocale) -> Result<Self, $error_ty> { |
282 | $($struct :: )? $unstable(&crate::provider::Baked, locale) |
283 | } |
284 | #[doc = $crate::gen_any_buffer_unstable_docs!(ANY, $($struct ::)? $baked)] |
285 | pub fn $any(provider: &(impl $crate::AnyProvider + ?Sized), locale: &$crate::DataLocale) -> Result<Self, $error_ty> { |
286 | use $crate::AsDowncastingAnyProvider; |
287 | $($struct :: )? $unstable(&provider.as_downcasting(), locale) |
288 | } |
289 | #[cfg(feature = "serde" )] |
290 | #[doc = $crate::gen_any_buffer_unstable_docs!(BUFFER, $($struct ::)? $baked)] |
291 | pub fn $buffer(provider: &(impl $crate::BufferProvider + ?Sized), locale: &$crate::DataLocale) -> Result<Self, $error_ty> { |
292 | use $crate::AsDeserializingBufferProvider; |
293 | $($struct :: )? $unstable(&provider.as_deserializing(), locale) |
294 | } |
295 | }; |
296 | |
297 | (locale: include, $config_arg:ident: $config_ty:path, $options_arg:ident: $options_ty:path, error: $error_ty:path, $(#[$doc:meta])+) => { |
298 | $crate::gen_any_buffer_data_constructors!( |
299 | locale: include, |
300 | $config_arg: $config_ty, |
301 | $options_arg: $options_ty, |
302 | error: $error_ty, |
303 | $(#[$doc])+ |
304 | functions: [ |
305 | try_new, |
306 | try_new_with_any_provider, |
307 | try_new_with_buffer_provider, |
308 | try_new_unstable, |
309 | Self, |
310 | ] |
311 | ); |
312 | }; |
313 | (locale: include, $config_arg:ident: $config_ty:path, $options_arg:ident: $options_ty:path, error: $error_ty:path, $(#[$doc:meta])+ functions: [$baked:ident, $any:ident, $buffer:ident, $unstable:ident $(, $struct:ident)? $(,)?]) => { |
314 | #[cfg(feature = "compiled_data" )] |
315 | $(#[$doc])+ |
316 | /// |
317 | /// ✨ *Enabled with the `compiled_data` Cargo feature.* |
318 | /// |
319 | /// [📚 Help choosing a constructor](icu_provider::constructors) |
320 | pub fn $baked(locale: &$crate::DataLocale, $config_arg: $config_ty, $options_arg: $options_ty) -> Result<Self, $error_ty> { |
321 | $($struct :: )? $unstable(&crate::provider::Baked, locale, $config_arg, $options_arg) |
322 | } |
323 | #[doc = $crate::gen_any_buffer_unstable_docs!(ANY, $($struct ::)? $baked)] |
324 | pub fn $any(provider: &(impl $crate::AnyProvider + ?Sized), locale: &$crate::DataLocale, $config_arg: $config_ty, $options_arg: $options_ty) -> Result<Self, $error_ty> { |
325 | use $crate::AsDowncastingAnyProvider; |
326 | $($struct :: )? $unstable(&provider.as_downcasting(), locale, $config_arg, $options_arg) |
327 | } |
328 | #[cfg(feature = "serde" )] |
329 | #[doc = $crate::gen_any_buffer_unstable_docs!(BUFFER, $($struct ::)? $baked)] |
330 | pub fn $buffer(provider: &(impl $crate::BufferProvider + ?Sized), locale: &$crate::DataLocale, $config_arg: $config_ty, $options_arg: $options_ty) -> Result<Self, $error_ty> { |
331 | use $crate::AsDeserializingBufferProvider; |
332 | $($struct :: )? $unstable(&provider.as_deserializing(), locale, $config_arg, $options_arg) |
333 | } |
334 | }; |
335 | |
336 | (locale: include, $options_arg:ident: $options_ty:path, error: $error_ty:path, $(#[$doc:meta])+) => { |
337 | $crate::gen_any_buffer_data_constructors!( |
338 | locale: include, |
339 | $options_arg: $options_ty, |
340 | error: $error_ty, |
341 | $(#[$doc])+ |
342 | functions: [ |
343 | try_new, |
344 | try_new_with_any_provider, |
345 | try_new_with_buffer_provider, |
346 | try_new_unstable, |
347 | Self, |
348 | ] |
349 | ); |
350 | }; |
351 | (locale: include, $options_arg:ident: $options_ty:path, error: $error_ty:path, $(#[$doc:meta])+ functions: [$baked:ident, $any:ident, $buffer:ident, $unstable:ident $(, $struct:ident)? $(,)?]) => { |
352 | #[cfg(feature = "compiled_data" )] |
353 | $(#[$doc])+ |
354 | /// |
355 | /// ✨ *Enabled with the `compiled_data` Cargo feature.* |
356 | /// |
357 | /// [📚 Help choosing a constructor](icu_provider::constructors) |
358 | pub fn $baked(locale: &$crate::DataLocale, $options_arg: $options_ty) -> Result<Self, $error_ty> { |
359 | $($struct :: )? $unstable(&crate::provider::Baked, locale, $options_arg) |
360 | } |
361 | #[doc = $crate::gen_any_buffer_unstable_docs!(ANY, $($struct ::)? $baked)] |
362 | pub fn $any(provider: &(impl $crate::AnyProvider + ?Sized), locale: &$crate::DataLocale, $options_arg: $options_ty) -> Result<Self, $error_ty> { |
363 | use $crate::AsDowncastingAnyProvider; |
364 | $($struct :: )? $unstable(&provider.as_downcasting(), locale, $options_arg) |
365 | } |
366 | #[cfg(feature = "serde" )] |
367 | #[doc = $crate::gen_any_buffer_unstable_docs!(BUFFER, $($struct ::)? $baked)] |
368 | pub fn $buffer(provider: &(impl $crate::BufferProvider + ?Sized), locale: &$crate::DataLocale, $options_arg: $options_ty) -> Result<Self, $error_ty> { |
369 | use $crate::AsDeserializingBufferProvider; |
370 | $($struct :: )? $unstable(&provider.as_deserializing(), locale, $options_arg) |
371 | } |
372 | }; |
373 | } |
374 | |