1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
// 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 ).
//! Collection of predicate traits and functions for forking providers.
use icu_provider::prelude::*;
/// The predicate trait used by [`ForkByErrorProvider`].
///
/// [`ForkByErrorProvider`]: super::ForkByErrorProvider
pub trait ForkByErrorPredicate {
/// The error to return if there are zero providers.
const UNIT_ERROR: DataErrorKind = DataErrorKind::MarkerNotFound;
/// This function is called when a data request fails and there are additional providers
/// that could possibly fulfill the request.
///
/// Arguments:
///
/// - `&self` = Reference to the struct implementing the trait (for data capture)
/// - `marker` = The [`DataMarkerInfo`] associated with the request
/// - `req` = The [`DataRequest`]. This may be `None` if there is no request, such as
/// inside [`IterableDynamicDataProvider`].
/// - `err` = The error that occurred.
///
/// Return value:
///
/// - `true` to discard the error and attempt the request with the next provider.
/// - `false` to return the error and not perform any additional requests.
fn test(&self, marker: DataMarkerInfo, req: Option<DataRequest>, err: DataError) -> bool;
}
/// A predicate that allows forking providers to search for a provider that supports a
/// particular data marker.
///
/// This is normally used implicitly by [`ForkByMarkerProvider`].
///
/// [`ForkByMarkerProvider`]: super::ForkByMarkerProvider
#[derive(Debug, PartialEq, Eq)]
#[non_exhaustive] // Not intended to be constructed
pub struct MarkerNotFoundPredicate;
impl ForkByErrorPredicate for MarkerNotFoundPredicate {
const UNIT_ERROR: DataErrorKind = DataErrorKind::MarkerNotFound;
#[inline]
fn test(&self, _: DataMarkerInfo, _: Option<DataRequest>, err: DataError) -> bool {
matches!(
err,
DataError {
kind: DataErrorKind::MarkerNotFound,
..
}
)
}
}
/// A predicate that allows forking providers to search for a provider that supports a
/// particular locale, based on whether it returns [`DataErrorKind::IdentifierNotFound`].
///
/// # Examples
///
/// ```
/// use icu_provider_adapters::fork::ForkByErrorProvider;
/// use icu_provider_adapters::fork::predicates::IdentifierNotFoundPredicate;
/// use icu_provider::prelude::*;
/// use icu_provider::hello_world::*;
/// use icu_locale::langid;
///
/// struct SingleLocaleProvider(DataLocale);
/// impl DataProvider<HelloWorldV1Marker> for SingleLocaleProvider {
/// fn load(&self, req: DataRequest) -> Result<DataResponse<HelloWorldV1Marker>, DataError> {
/// if *req.id.locale != self.0 {
/// return Err(DataErrorKind::IdentifierNotFound.with_req(HelloWorldV1Marker::INFO, req));
/// }
/// HelloWorldProvider.load(req)
/// }
/// }
///
/// let provider_de = SingleLocaleProvider(langid!("de").into());
/// let provider_ro = SingleLocaleProvider(langid!("ro").into());
///
/// // Create the forking provider:
/// let provider = ForkByErrorProvider::new_with_predicate(
/// provider_de,
/// provider_ro,
/// IdentifierNotFoundPredicate
/// );
///
/// // Test that we can load both "de" and "ro" data:
///
/// let german_hello_world: DataResponse<HelloWorldV1Marker> = provider
/// .load(DataRequest {
/// id: DataIdentifierBorrowed::for_locale(&langid!("de").into()),
/// ..Default::default()
/// })
/// .expect("Loading should succeed");
///
/// assert_eq!("Hallo Welt", german_hello_world.payload.get().message);
///
/// let romanian_hello_world: DataResponse<HelloWorldV1Marker> = provider
/// .load(DataRequest {
/// id: DataIdentifierBorrowed::for_locale(&langid!("ro").into()),
/// ..Default::default()
/// })
/// .expect("Loading should succeed");
///
/// assert_eq!("Salut, lume", romanian_hello_world.payload.get().message);
///
/// // We should not be able to load "en" data because it is not in either provider:
///
/// DataProvider::<HelloWorldV1Marker>::load(
/// &provider,
/// DataRequest {
/// id: DataIdentifierBorrowed::for_locale(&langid!("en").into()),
/// ..Default::default()
/// }
/// )
/// .expect_err("No English data");
/// ```
#[derive(Debug, PartialEq, Eq)]
#[allow(clippy::exhaustive_structs)] // empty type
pub struct IdentifierNotFoundPredicate;
impl ForkByErrorPredicate for IdentifierNotFoundPredicate {
const UNIT_ERROR: DataErrorKind = DataErrorKind::IdentifierNotFound;
#[inline]
fn test(&self, _: DataMarkerInfo, _: Option<DataRequest>, err: DataError) -> bool {
Err::<(), _>(err).allow_identifier_not_found().is_ok()
}
}