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