summaryrefslogtreecommitdiffstats
path: root/vendor/icu_provider_adapters/src/fork/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/icu_provider_adapters/src/fork/mod.rs')
-rw-r--r--vendor/icu_provider_adapters/src/fork/mod.rs226
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)
+ }
+}