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