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]
116macro_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]
145macro_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