• 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 //! Providers that combine multiple other providers.
6 //!
7 //! # Types of Forking Providers
8 //!
9 //! ## Marker-Based
10 //!
11 //! To fork between providers that support different data markers, see:
12 //!
13 //! - [`ForkByMarkerProvider`]
14 //! - [`MultiForkByMarkerProvider`]
15 //!
16 //! ## Locale-Based
17 //!
18 //! To fork between providers that support different locales, see:
19 //!
20 //! - [`ForkByErrorProvider`]`<`[`IdentiferNotFoundPredicate`]`>`
21 //! - [`MultiForkByErrorProvider`]`<`[`IdentiferNotFoundPredicate`]`>`
22 //!
23 //! [`IdentiferNotFoundPredicate`]: predicates::IdentifierNotFoundPredicate
24 //!
25 //! # Examples
26 //!
27 //! See:
28 //!
29 //! - [`ForkByMarkerProvider`]
30 //! - [`MultiForkByMarkerProvider`]
31 //! - [`IdentiferNotFoundPredicate`]
32 
33 use alloc::vec::Vec;
34 
35 mod by_error;
36 
37 pub mod predicates;
38 
39 pub use by_error::ForkByErrorProvider;
40 pub use by_error::MultiForkByErrorProvider;
41 
42 use predicates::ForkByErrorPredicate;
43 use predicates::MarkerNotFoundPredicate;
44 
45 /// Create a provider that returns data from one of two child providers based on the marker.
46 ///
47 /// The result of the first provider that supports a particular [`DataMarkerInfo`] will be returned,
48 /// even if the request failed for other reasons (such as an unsupported language). Therefore,
49 /// you should add child providers that support disjoint sets of markers.
50 ///
51 /// [`ForkByMarkerProvider`] does not support forking between [`DataProvider`]s. However, it
52 /// supports forking between [`BufferProvider`], and [`DynamicDataProvider`].
53 ///
54 /// # Examples
55 ///
56 /// Normal usage:
57 ///
58 /// ```
59 /// use icu_locale::langid;
60 /// use icu_provider::hello_world::*;
61 /// use icu_provider::prelude::*;
62 /// use icu_provider_adapters::fork::ForkByMarkerProvider;
63 ///
64 /// struct DummyBufferProvider;
65 /// impl DynamicDataProvider<BufferMarker> for DummyBufferProvider {
66 ///     fn load_data(
67 ///         &self,
68 ///         marker: DataMarkerInfo,
69 ///         req: DataRequest,
70 ///     ) -> Result<DataResponse<BufferMarker>, DataError> {
71 ///         Err(DataErrorKind::MarkerNotFound.with_req(marker, req))
72 ///     }
73 /// }
74 ///
75 /// let forking_provider = ForkByMarkerProvider::new(
76 ///     DummyBufferProvider,
77 ///     HelloWorldProvider.into_json_provider(),
78 /// );
79 ///
80 /// let provider = forking_provider.as_deserializing();
81 ///
82 /// let german_hello_world: DataResponse<HelloWorldV1> = provider
83 ///     .load(DataRequest {
84 ///         id: DataIdentifierBorrowed::for_locale(&langid!("de").into()),
85 ///         ..Default::default()
86 ///     })
87 ///     .expect("Loading should succeed");
88 ///
89 /// assert_eq!("Hallo Welt", german_hello_world.payload.get().message);
90 /// ```
91 ///
92 /// Stops at the first provider supporting a marker, even if the locale is not supported:
93 ///
94 /// ```
95 /// use icu_locale::{subtags::language, langid};
96 /// use icu_provider::hello_world::*;
97 /// use icu_provider::prelude::*;
98 /// use icu_provider_adapters::filter::FilterDataProvider;
99 /// use icu_provider_adapters::fork::ForkByMarkerProvider;
100 ///
101 /// let forking_provider = ForkByMarkerProvider::new(
102 ///     FilterDataProvider::new(
103 ///         HelloWorldProvider.into_json_provider(),
104 ///         "Chinese"
105 ///     )
106 ///     .with_filter(|id| id.locale.language == language!("zh")),
107 ///     FilterDataProvider::new(
108 ///         HelloWorldProvider.into_json_provider(),
109 ///         "German"
110 ///     )
111 ///     .with_filter(|id| id.locale.language == language!("de")),
112 /// );
113 ///
114 /// let provider: &dyn DataProvider<HelloWorldV1> =
115 ///     &forking_provider.as_deserializing();
116 ///
117 /// // Chinese is the first provider, so this succeeds
118 /// let chinese_hello_world = provider
119 ///     .load(DataRequest {
120 ///         id: DataIdentifierBorrowed::for_locale(&langid!("zh").into()),
121 ///         ..Default::default()
122 ///     })
123 ///     .expect("Loading should succeed");
124 ///
125 /// assert_eq!("你好世界", chinese_hello_world.payload.get().message);
126 ///
127 /// // German is shadowed by Chinese, so this fails
128 /// provider
129 ///     .load(DataRequest {
130 ///         id: DataIdentifierBorrowed::for_locale(&langid!("de").into()),
131 ///         ..Default::default()
132 ///     })
133 ///     .expect_err("Should stop at the first provider, even though the second has data");
134 /// ```
135 ///
136 /// [`DataMarkerInfo`]: icu_provider::DataMarkerInfo
137 /// [`DataProvider`]: icu_provider::DataProvider
138 /// [`BufferProvider`]: icu_provider::buf::BufferProvider
139 /// [`DynamicDataProvider`]: icu_provider::DynamicDataProvider
140 pub type ForkByMarkerProvider<P0, P1> = ForkByErrorProvider<P0, P1, MarkerNotFoundPredicate>;
141 
142 impl<P0, P1> ForkByMarkerProvider<P0, P1> {
143     /// A provider that returns data from one of two child providers based on the marker.
144     ///
145     /// See [`ForkByMarkerProvider`].
new(p0: P0, p1: P1) -> Self146     pub fn new(p0: P0, p1: P1) -> Self {
147         ForkByErrorProvider::new_with_predicate(p0, p1, MarkerNotFoundPredicate)
148     }
149 }
150 
151 /// A provider that returns data from the first child provider supporting the marker.
152 ///
153 /// The result of the first provider that supports a particular [`DataMarkerInfo`] will be returned,
154 /// even if the request failed for other reasons (such as an unsupported language). Therefore,
155 /// you should add child providers that support disjoint sets of markers.
156 ///
157 /// [`MultiForkByMarkerProvider`] does not support forking between [`DataProvider`]s. However, it
158 /// supports forking between [`BufferProvider`], and [`DynamicDataProvider`].
159 ///
160 /// # Examples
161 ///
162 /// ```
163 /// use icu_locale::{subtags::language, langid};
164 /// use icu_provider::hello_world::*;
165 /// use icu_provider::prelude::*;
166 /// use icu_provider_adapters::filter::FilterDataProvider;
167 /// use icu_provider_adapters::fork::MultiForkByMarkerProvider;
168 ///
169 /// let forking_provider = MultiForkByMarkerProvider::new(
170 ///     vec![
171 ///         FilterDataProvider::new(
172 ///             HelloWorldProvider.into_json_provider(),
173 ///             "Chinese"
174 ///         )
175 ///         .with_filter(|id| id.locale.language == language!("zh")),
176 ///         FilterDataProvider::new(
177 ///             HelloWorldProvider.into_json_provider(),
178 ///             "German"
179 ///         )
180 ///         .with_filter(|id| id.locale.language == language!("de")),
181 ///     ],
182 /// );
183 ///
184 /// let provider: &dyn DataProvider<HelloWorldV1> =
185 ///     &forking_provider.as_deserializing();
186 ///
187 /// // Chinese is the first provider, so this succeeds
188 /// let chinese_hello_world = provider
189 ///     .load(DataRequest {
190 ///         id: DataIdentifierBorrowed::for_locale(&langid!("zh").into()),
191 ///         ..Default::default()
192 ///     })
193 ///     .expect("Loading should succeed");
194 ///
195 /// assert_eq!("你好世界", chinese_hello_world.payload.get().message);
196 ///
197 /// // German is shadowed by Chinese, so this fails
198 /// provider
199 ///     .load(DataRequest {
200 ///         id: DataIdentifierBorrowed::for_locale(&langid!("de").into()),
201 ///         ..Default::default()
202 ///     })
203 ///     .expect_err("Should stop at the first provider, even though the second has data");
204 /// ```
205 ///
206 /// [`DataMarkerInfo`]: icu_provider::DataMarkerInfo
207 /// [`DataProvider`]: icu_provider::DataProvider
208 /// [`BufferProvider`]: icu_provider::buf::BufferProvider
209 /// [`DynamicDataProvider`]: icu_provider::DynamicDataProvider
210 pub type MultiForkByMarkerProvider<P> = MultiForkByErrorProvider<P, MarkerNotFoundPredicate>;
211 
212 impl<P> MultiForkByMarkerProvider<P> {
213     /// Create a provider that returns data from the first child provider supporting the marker.
214     ///
215     /// See [`MultiForkByMarkerProvider`].
new(providers: Vec<P>) -> Self216     pub fn new(providers: Vec<P>) -> Self {
217         MultiForkByErrorProvider::new_with_predicate(providers, MarkerNotFoundPredicate)
218     }
219 }
220