diff options
Diffstat (limited to 'vendor/icu_provider_adapters/src/fork/mod.rs')
-rw-r--r-- | vendor/icu_provider_adapters/src/fork/mod.rs | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/vendor/icu_provider_adapters/src/fork/mod.rs b/vendor/icu_provider_adapters/src/fork/mod.rs new file mode 100644 index 000000000..05ba5fd19 --- /dev/null +++ b/vendor/icu_provider_adapters/src/fork/mod.rs @@ -0,0 +1,226 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! Providers that combine multiple other providers. +//! +//! # Types of Forking Providers +//! +//! ## Key-Based +//! +//! To fork between providers that support different data keys, see: +//! +//! - [`ForkByKeyProvider`] +//! - [`MultiForkByKeyProvider`] +//! +//! ## Locale-Based +//! +//! To fork between providers that support different locales, see: +//! +//! - [`ForkByErrorProvider`]`<`[`MissingLocalePredicate`]`>` +//! - [`MultiForkByErrorProvider`]`<`[`MissingLocalePredicate`]`>` +//! +//! [`MissingLocalePredicate`]: predicates::MissingLocalePredicate +//! +//! # Examples +//! +//! See: +//! +//! - [`ForkByKeyProvider`] +//! - [`MultiForkByKeyProvider`] +//! - [`MissingLocalePredicate`] + +use alloc::vec::Vec; + +mod by_error; + +pub mod predicates; + +#[macro_use] +mod macros; + +pub use by_error::ForkByErrorProvider; +pub use by_error::MultiForkByErrorProvider; + +use predicates::ForkByErrorPredicate; +use predicates::MissingDataKeyPredicate; + +/// Create a provider that returns data from one of two child providers based on the key. +/// +/// The result of the first provider that supports a particular [`DataKey`] will be returned, +/// even if the request failed for other reasons (such as an unsupported language). Therefore, +/// you should add child providers that support disjoint sets of keys. +/// +/// [`ForkByKeyProvider`] does not support forking between [`DataProvider`]s. However, it +/// supports forking between [`AnyProvider`], [`BufferProvider`], and [`DynamicDataProvider`]. +/// +/// # Examples +/// +/// Normal usage: +/// +/// ``` +/// use icu_locid::locale; +/// use icu_provider::hello_world::*; +/// use icu_provider::prelude::*; +/// use icu_provider_adapters::fork::ForkByKeyProvider; +/// +/// struct DummyBufferProvider; +/// impl BufferProvider for DummyBufferProvider { +/// fn load_buffer( +/// &self, +/// key: DataKey, +/// req: DataRequest, +/// ) -> Result<DataResponse<BufferMarker>, DataError> { +/// Err(DataErrorKind::MissingDataKey.with_req(key, req)) +/// } +/// } +/// +/// let forking_provider = ForkByKeyProvider::new( +/// DummyBufferProvider, +/// HelloWorldProvider.into_json_provider(), +/// ); +/// +/// let data_provider = forking_provider.as_deserializing(); +/// +/// let german_hello_world: DataPayload<HelloWorldV1Marker> = data_provider +/// .load(DataRequest { +/// locale: &locale!("de").into(), +/// metadata: Default::default(), +/// }) +/// .expect("Loading should succeed") +/// .take_payload() +/// .expect("Data should be present"); +/// +/// assert_eq!("Hallo Welt", german_hello_world.get().message); +/// ``` +/// +/// Stops at the first provider supporting a key, even if the locale is not supported: +/// +/// ``` +/// use icu_locid::{subtags_language as language, locale}; +/// use icu_provider::hello_world::*; +/// use icu_provider::prelude::*; +/// use icu_provider_adapters::filter::Filterable; +/// use icu_provider_adapters::fork::ForkByKeyProvider; +/// +/// let forking_provider = ForkByKeyProvider::new( +/// HelloWorldProvider +/// .into_json_provider() +/// .filterable("Chinese") +/// .filter_by_langid(|langid| langid.language == language!("zh")), +/// HelloWorldProvider +/// .into_json_provider() +/// .filterable("German") +/// .filter_by_langid(|langid| langid.language == language!("de")), +/// ); +/// +/// let data_provider: &dyn DataProvider<HelloWorldV1Marker> = +/// &forking_provider.as_deserializing(); +/// +/// // Chinese is the first provider, so this succeeds +/// let chinese_hello_world = data_provider +/// .load(DataRequest { +/// locale: &locale!("zh").into(), +/// metadata: Default::default(), +/// }) +/// .expect("Loading should succeed") +/// .take_payload() +/// .expect("Data should be present"); +/// +/// assert_eq!("你好世界", chinese_hello_world.get().message); +/// +/// // German is shadowed by Chinese, so this fails +/// data_provider +/// .load(DataRequest { +/// locale: &locale!("de").into(), +/// metadata: Default::default(), +/// }) +/// .expect_err("Should stop at the first provider, even though the second has data"); +/// ``` +/// +/// [`DataKey`]: icu_provider::DataKey +/// [`DataProvider`]: icu_provider::DataProvider +/// [`AnyProvider`]: icu_provider::AnyProvider +/// [`BufferProvider`]: icu_provider::BufferProvider +/// [`DynamicDataProvider`]: icu_provider::DynamicDataProvider +pub type ForkByKeyProvider<P0, P1> = ForkByErrorProvider<P0, P1, MissingDataKeyPredicate>; + +impl<P0, P1> ForkByKeyProvider<P0, P1> { + /// A provider that returns data from one of two child providers based on the key. + /// + /// See [`ForkByKeyProvider`]. + pub fn new(p0: P0, p1: P1) -> Self { + ForkByErrorProvider::new_with_predicate(p0, p1, MissingDataKeyPredicate) + } +} + +/// A provider that returns data from the first child provider supporting the key. +/// +/// The result of the first provider that supports a particular [`DataKey`] will be returned, +/// even if the request failed for other reasons (such as an unsupported language). Therefore, +/// you should add child providers that support disjoint sets of keys. +/// +/// [`MultiForkByKeyProvider`] does not support forking between [`DataProvider`]s. However, it +/// supports forking between [`AnyProvider`], [`BufferProvider`], and [`DynamicDataProvider`]. +/// +/// # Examples +/// +/// ``` +/// use icu_locid::{subtags_language as language, locale}; +/// use icu_provider::hello_world::*; +/// use icu_provider::prelude::*; +/// use icu_provider_adapters::filter::Filterable; +/// use icu_provider_adapters::fork::MultiForkByKeyProvider; +/// +/// let forking_provider = MultiForkByKeyProvider::new( +/// vec![ +/// HelloWorldProvider +/// .into_json_provider() +/// .filterable("Chinese") +/// .filter_by_langid(|langid| langid.language == language!("zh")), +/// HelloWorldProvider +/// .into_json_provider() +/// .filterable("German") +/// .filter_by_langid(|langid| langid.language == language!("de")), +/// ], +/// ); +/// +/// let data_provider: &dyn DataProvider<HelloWorldV1Marker> = +/// &forking_provider.as_deserializing(); +/// +/// // Chinese is the first provider, so this succeeds +/// let chinese_hello_world = data_provider +/// .load(DataRequest { +/// locale: &locale!("zh").into(), +/// metadata: Default::default(), +/// }) +/// .expect("Loading should succeed") +/// .take_payload() +/// .expect("Data should be present"); +/// +/// assert_eq!("你好世界", chinese_hello_world.get().message); +/// +/// // German is shadowed by Chinese, so this fails +/// data_provider +/// .load(DataRequest { +/// locale: &locale!("de").into(), +/// metadata: Default::default(), +/// }) +/// .expect_err("Should stop at the first provider, even though the second has data"); +/// ``` +/// +/// [`DataKey`]: icu_provider::DataKey +/// [`DataProvider`]: icu_provider::DataProvider +/// [`AnyProvider`]: icu_provider::AnyProvider +/// [`BufferProvider`]: icu_provider::BufferProvider +/// [`DynamicDataProvider`]: icu_provider::DynamicDataProvider +pub type MultiForkByKeyProvider<P> = MultiForkByErrorProvider<P, MissingDataKeyPredicate>; + +impl<P> MultiForkByKeyProvider<P> { + /// Create a provider that returns data from the first child provider supporting the key. + /// + /// See [`MultiForkByKeyProvider`]. + pub fn new(providers: Vec<P>) -> Self { + MultiForkByErrorProvider::new_with_predicate(providers, MissingDataKeyPredicate) + } +} |