icu_provider/
constructors.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//! 📚 *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}