/rust/registry/src/index.crates.io-1949cf8c6b5b557f/icu_provider-2.2.0/src/response.rs
Line | Count | Source |
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 | | use crate::buf::BufferMarker; |
6 | | use crate::DataError; |
7 | | use crate::DataLocale; |
8 | | use crate::DynamicDataMarker; |
9 | | #[cfg(feature = "alloc")] |
10 | | use alloc::boxed::Box; |
11 | | use core::fmt::Debug; |
12 | | use core::marker::PhantomData; |
13 | | #[cfg(feature = "alloc")] |
14 | | use core::ops::Deref; |
15 | | use yoke::cartable_ptr::CartableOptionPointer; |
16 | | use yoke::*; |
17 | | |
18 | | #[cfg(feature = "alloc")] |
19 | | #[cfg(not(feature = "sync"))] |
20 | | use alloc::rc::Rc as SelectedRc; |
21 | | #[cfg(feature = "alloc")] |
22 | | #[cfg(feature = "sync")] |
23 | | use alloc::sync::Arc as SelectedRc; |
24 | | |
25 | | /// A response object containing metadata about the returned data. |
26 | | #[derive(Debug, Clone, PartialEq, Default)] |
27 | | #[non_exhaustive] |
28 | | pub struct DataResponseMetadata { |
29 | | /// The resolved locale of the returned data, if locale fallbacking was performed. |
30 | | pub locale: Option<DataLocale>, |
31 | | /// The format of the buffer for buffer-backed data, if known (for example, JSON). |
32 | | pub buffer_format: Option<crate::buf::BufferFormat>, |
33 | | /// An optional checksum. This can be used to ensure consistency across different markers. |
34 | | pub checksum: Option<u64>, |
35 | | } |
36 | | |
37 | | impl DataResponseMetadata { |
38 | | /// Sets the checksum. |
39 | 0 | pub fn with_checksum(self, checksum: u64) -> Self { |
40 | 0 | Self { |
41 | 0 | checksum: Some(checksum), |
42 | 0 | ..self |
43 | 0 | } |
44 | 0 | } |
45 | | } |
46 | | |
47 | | /// A container for data payloads returned from a data provider. |
48 | | /// |
49 | | /// [`DataPayload`] is built on top of the [`yoke`] framework, which allows for cheap, zero-copy |
50 | | /// operations on data via the use of self-references. |
51 | | /// |
52 | | /// The type of the data stored in [`DataPayload`] is determined by the [`DynamicDataMarker`] type parameter. |
53 | | /// |
54 | | /// ## Accessing the data |
55 | | /// |
56 | | /// To get a reference to the data inside [`DataPayload`], use [`DataPayload::get()`]. If you need |
57 | | /// to store the data for later use, you need to store the [`DataPayload`] itself, since `get` only |
58 | | /// returns a reference with an ephemeral lifetime. |
59 | | /// |
60 | | /// ## Mutating the data |
61 | | /// |
62 | | /// To modify the data stored in a [`DataPayload`], use [`DataPayload::with_mut()`]. |
63 | | /// |
64 | | /// ## Transforming the data to a different type |
65 | | /// |
66 | | /// To transform a [`DataPayload`] to a different type backed by the same data store (cart), use |
67 | | /// [`DataPayload::map_project()`] or one of its sister methods. |
68 | | /// |
69 | | /// # Cargo feature: `sync` |
70 | | /// |
71 | | /// By default, the payload uses non-concurrent reference counting internally, and hence is neither |
72 | | /// [`Sync`] nor [`Send`]; if these traits are required, the `sync` Cargo feature can be enabled. |
73 | | /// |
74 | | /// # Examples |
75 | | /// |
76 | | /// Basic usage, using the `HelloWorldV1` marker: |
77 | | /// |
78 | | /// ``` |
79 | | /// use icu_provider::hello_world::*; |
80 | | /// use icu_provider::prelude::*; |
81 | | /// use std::borrow::Cow; |
82 | | /// |
83 | | /// let payload = DataPayload::<HelloWorldV1>::from_owned(HelloWorld { |
84 | | /// message: Cow::Borrowed("Demo"), |
85 | | /// }); |
86 | | /// |
87 | | /// assert_eq!("Demo", payload.get().message); |
88 | | /// ``` |
89 | | pub struct DataPayload<M: DynamicDataMarker>(pub(crate) DataPayloadInner<M>); |
90 | | |
91 | | /// A container for data payloads with storage for something else. |
92 | | /// |
93 | | /// The type parameter `O` is stored as part of the interior enum, leading to |
94 | | /// better stack size optimization. `O` can be as large as the [`DataPayload`] |
95 | | /// minus two words without impacting stack size. |
96 | | /// |
97 | | /// # Examples |
98 | | /// |
99 | | /// Create and use [`DataPayloadOr`]: |
100 | | /// |
101 | | /// ``` |
102 | | /// use icu_locale_core::langid; |
103 | | /// use icu_provider::hello_world::*; |
104 | | /// use icu_provider::prelude::*; |
105 | | /// use icu_provider::DataPayloadOr; |
106 | | /// |
107 | | /// let response: DataResponse<HelloWorldV1> = HelloWorldProvider |
108 | | /// .load(DataRequest { |
109 | | /// id: DataIdentifierBorrowed::for_locale(&langid!("de").into()), |
110 | | /// ..Default::default() |
111 | | /// }) |
112 | | /// .expect("Loading should succeed"); |
113 | | /// |
114 | | /// let payload_some = |
115 | | /// DataPayloadOr::<HelloWorldV1, ()>::from_payload(response.payload); |
116 | | /// let payload_none = DataPayloadOr::<HelloWorldV1, ()>::from_other(()); |
117 | | /// |
118 | | /// assert_eq!( |
119 | | /// payload_some.get(), |
120 | | /// Ok(&HelloWorld { |
121 | | /// message: "Hallo Welt".into() |
122 | | /// }) |
123 | | /// ); |
124 | | /// assert_eq!(payload_none.get(), Err(&())); |
125 | | /// ``` |
126 | | /// |
127 | | /// Stack size comparison: |
128 | | /// |
129 | | /// ``` |
130 | | /// use icu_provider::prelude::*; |
131 | | /// use icu_provider::DataPayloadOr; |
132 | | /// |
133 | | /// const W: usize = size_of::<usize>(); |
134 | | /// |
135 | | /// // Data struct is 3 words: |
136 | | /// icu_provider::data_marker!(SampleV1, [usize; 3]); |
137 | | /// |
138 | | /// // DataPayload adds a word for a total of 4 words: |
139 | | /// assert_eq!(W * 4, size_of::<DataPayload<SampleV1>>()); |
140 | | /// |
141 | | /// // Option<DataPayload> balloons to 5 words: |
142 | | /// assert_eq!(W * 5, size_of::<Option<DataPayload<SampleV1>>>()); |
143 | | /// |
144 | | /// // But, using DataPayloadOr is the same size as DataPayload: |
145 | | /// assert_eq!(W * 4, size_of::<DataPayloadOr<SampleV1, ()>>()); |
146 | | /// |
147 | | /// // The largest optimized Other type is two words smaller than the DataPayload: |
148 | | /// assert_eq!(W * 4, size_of::<DataPayloadOr<SampleV1, [usize; 1]>>()); |
149 | | /// assert_eq!(W * 4, size_of::<DataPayloadOr<SampleV1, [usize; 2]>>()); |
150 | | /// assert_eq!(W * 5, size_of::<DataPayloadOr<SampleV1, [usize; 3]>>()); |
151 | | /// ``` |
152 | | pub struct DataPayloadOr<M: DynamicDataMarker, O>(pub(crate) DataPayloadOrInner<M, O>); |
153 | | |
154 | | pub(crate) enum DataPayloadInner<M: DynamicDataMarker> { |
155 | | Yoke(Yoke<M::DataStruct, CartableOptionPointer<CartInner>>), |
156 | | StaticRef(&'static M::DataStruct), |
157 | | } |
158 | | |
159 | | pub(crate) enum DataPayloadOrInner<M: DynamicDataMarker, O> { |
160 | | Yoke(Yoke<M::DataStruct, CartableOptionPointer<CartInner>>), |
161 | | Inner(DataPayloadOrInnerInner<M, O>), |
162 | | } |
163 | | |
164 | | pub(crate) enum DataPayloadOrInnerInner<M: DynamicDataMarker, O> { |
165 | | StaticRef(&'static M::DataStruct), |
166 | | Other(O), |
167 | | } |
168 | | |
169 | | /// The type of the "cart" that is used by [`DataPayload`]. |
170 | | /// |
171 | | /// This type is public but the inner cart type is private. To create a |
172 | | /// [`Yoke`] with this cart, use [`Cart::try_make_yoke`]. Then, convert |
173 | | /// it to a [`DataPayload`] with [`DataPayload::from_yoked_buffer`]. |
174 | | #[derive(Clone, Debug)] |
175 | | pub struct Cart(#[allow(dead_code)] CartInner); |
176 | | |
177 | | /// The actual cart type (private typedef). |
178 | | #[cfg(feature = "alloc")] |
179 | | pub(crate) type CartInner = SelectedRc<Box<[u8]>>; |
180 | | #[cfg(not(feature = "alloc"))] |
181 | | pub(crate) type CartInner = &'static (); |
182 | | |
183 | | // Safety: Rc, Arc, and () are CloneableCart, and our impl delegates. |
184 | | unsafe impl CloneableCart for Cart {} |
185 | | |
186 | | #[cfg(feature = "alloc")] |
187 | | impl Deref for Cart { |
188 | | type Target = Box<[u8]>; |
189 | | fn deref(&self) -> &Self::Target { |
190 | | &self.0 |
191 | | } |
192 | | } |
193 | | // Safety: both Rc and Arc are StableDeref, and our impl delegates. |
194 | | #[cfg(feature = "alloc")] |
195 | | unsafe impl stable_deref_trait::StableDeref for Cart {} |
196 | | |
197 | | impl Cart { |
198 | | #[cfg(feature = "alloc")] |
199 | | /// Creates a `Yoke<Y, Option<Cart>>` from owned bytes by applying `f`. |
200 | | /// |
201 | | /// ✨ *Enabled with the `alloc` Cargo feature.* |
202 | | pub fn try_make_yoke<Y, F, E>(cart: Box<[u8]>, f: F) -> Result<Yoke<Y, Option<Self>>, E> |
203 | | where |
204 | | for<'a> Y: Yokeable<'a>, |
205 | | F: FnOnce(&[u8]) -> Result<<Y as Yokeable>::Output, E>, |
206 | | { |
207 | | Yoke::try_attach_to_cart(SelectedRc::new(cart), |b| f(b)) |
208 | | // Safety: The cart is only wrapped, no data is leaked |
209 | | .map(|yoke| unsafe { yoke.replace_cart(Cart) }) |
210 | | .map(Yoke::wrap_cart_in_option) |
211 | | } |
212 | | |
213 | | /// Helper function to convert `Yoke<Y, Option<Cart>>` to `Yoke<Y, Option<CartInner>>`. |
214 | | #[inline] |
215 | 0 | pub(crate) fn unwrap_cart<Y>(yoke: Yoke<Y, Option<Cart>>) -> Yoke<Y, Option<CartInner>> |
216 | 0 | where |
217 | 0 | for<'a> Y: Yokeable<'a>, |
218 | | { |
219 | | // Safety: `Cart` has one field and we are removing it from the newtype, |
220 | | // and we are preserving it in the new cart, unwrapping it from the newtype. |
221 | 0 | unsafe { yoke.replace_cart(|option_cart| option_cart.map(|cart| cart.0)) } |
222 | 0 | } |
223 | | } |
224 | | |
225 | | impl<M> Debug for DataPayload<M> |
226 | | where |
227 | | M: DynamicDataMarker, |
228 | | for<'a> &'a <M::DataStruct as Yokeable<'a>>::Output: Debug, |
229 | | { |
230 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
231 | 0 | self.get().fmt(f) |
232 | 0 | } |
233 | | } |
234 | | |
235 | | impl<M, O> Debug for DataPayloadOr<M, O> |
236 | | where |
237 | | M: DynamicDataMarker, |
238 | | for<'a> &'a <M::DataStruct as Yokeable<'a>>::Output: Debug, |
239 | | O: Debug, |
240 | | { |
241 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
242 | 0 | self.get() |
243 | 0 | .map(|v| Debug::fmt(&v, f)) |
244 | 0 | .unwrap_or_else(|v| Debug::fmt(v, f)) |
245 | 0 | } |
246 | | } |
247 | | |
248 | | /// Cloning a [`DataPayload`] is generally a cheap operation. |
249 | | /// See notes in the `Clone` impl for [`Yoke`]. |
250 | | /// |
251 | | /// # Examples |
252 | | /// |
253 | | /// ```no_run |
254 | | /// use icu_provider::hello_world::*; |
255 | | /// use icu_provider::prelude::*; |
256 | | /// |
257 | | /// let resp1: DataPayload<HelloWorldV1> = todo!(); |
258 | | /// let resp2 = resp1.clone(); |
259 | | /// ``` |
260 | | impl<M> Clone for DataPayload<M> |
261 | | where |
262 | | M: DynamicDataMarker, |
263 | | for<'a> <M::DataStruct as Yokeable<'a>>::Output: Clone, |
264 | | { |
265 | 0 | fn clone(&self) -> Self { |
266 | 0 | Self(match &self.0 { |
267 | 0 | DataPayloadInner::Yoke(yoke) => DataPayloadInner::Yoke(yoke.clone()), |
268 | 0 | DataPayloadInner::StaticRef(r) => DataPayloadInner::StaticRef(*r), |
269 | | }) |
270 | 0 | } |
271 | | } |
272 | | |
273 | | impl<M, O> Clone for DataPayloadOr<M, O> |
274 | | where |
275 | | M: DynamicDataMarker, |
276 | | for<'a> <M::DataStruct as Yokeable<'a>>::Output: Clone, |
277 | | O: Clone, |
278 | | { |
279 | 0 | fn clone(&self) -> Self { |
280 | 0 | Self(match &self.0 { |
281 | 0 | DataPayloadOrInner::Yoke(yoke) => DataPayloadOrInner::Yoke(yoke.clone()), |
282 | 0 | DataPayloadOrInner::Inner(DataPayloadOrInnerInner::StaticRef(r)) => { |
283 | 0 | DataPayloadOrInner::Inner(DataPayloadOrInnerInner::StaticRef(*r)) |
284 | | } |
285 | 0 | DataPayloadOrInner::Inner(DataPayloadOrInnerInner::Other(o)) => { |
286 | 0 | DataPayloadOrInner::Inner(DataPayloadOrInnerInner::Other(o.clone())) |
287 | | } |
288 | | }) |
289 | 0 | } |
290 | | } |
291 | | |
292 | | impl<M> PartialEq for DataPayload<M> |
293 | | where |
294 | | M: DynamicDataMarker, |
295 | | for<'a> <M::DataStruct as Yokeable<'a>>::Output: PartialEq, |
296 | | { |
297 | 0 | fn eq(&self, other: &Self) -> bool { |
298 | 0 | self.get() == other.get() |
299 | 0 | } |
300 | | } |
301 | | impl<M, O> PartialEq for DataPayloadOr<M, O> |
302 | | where |
303 | | M: DynamicDataMarker, |
304 | | for<'a> <M::DataStruct as Yokeable<'a>>::Output: PartialEq, |
305 | | O: Eq, |
306 | | { |
307 | 0 | fn eq(&self, other: &Self) -> bool { |
308 | 0 | match (self.get(), other.get()) { |
309 | 0 | (Ok(x), Ok(y)) => x == y, |
310 | 0 | (Err(x), Err(y)) => x == y, |
311 | 0 | _ => false, |
312 | | } |
313 | 0 | } |
314 | | } |
315 | | |
316 | | impl<M> Eq for DataPayload<M> |
317 | | where |
318 | | M: DynamicDataMarker, |
319 | | for<'a> <M::DataStruct as Yokeable<'a>>::Output: Eq, |
320 | | { |
321 | | } |
322 | | |
323 | | impl<M, O> Eq for DataPayloadOr<M, O> |
324 | | where |
325 | | M: DynamicDataMarker, |
326 | | for<'a> <M::DataStruct as Yokeable<'a>>::Output: Eq, |
327 | | O: Eq, |
328 | | { |
329 | | } |
330 | | |
331 | | #[test] |
332 | | fn test_clone_eq() { |
333 | | use crate::hello_world::*; |
334 | | let p1 = DataPayload::<HelloWorldV1>::from_static_str("Demo"); |
335 | | let p2 = p1.clone(); |
336 | | assert_eq!(p1, p2); |
337 | | |
338 | | let p1 = DataPayloadOr::<HelloWorldV1, usize>::from_payload(p1); |
339 | | let p2 = p1.clone(); |
340 | | assert_eq!(p1, p2); |
341 | | |
342 | | let p3 = DataPayloadOr::<HelloWorldV1, usize>::from_other(555); |
343 | | let p4 = p3.clone(); |
344 | | assert_eq!(p3, p4); |
345 | | |
346 | | let p5 = DataPayloadOr::<HelloWorldV1, usize>::from_other(666); |
347 | | assert_ne!(p3, p5); |
348 | | assert_ne!(p4, p5); |
349 | | |
350 | | assert_ne!(p1, p3); |
351 | | assert_ne!(p1, p4); |
352 | | assert_ne!(p1, p5); |
353 | | assert_ne!(p2, p3); |
354 | | assert_ne!(p2, p4); |
355 | | assert_ne!(p2, p5); |
356 | | } |
357 | | |
358 | | impl<M> DataPayload<M> |
359 | | where |
360 | | M: DynamicDataMarker, |
361 | | { |
362 | | /// Convert a fully owned (`'static`) data struct into a [`DataPayload`]. |
363 | | /// |
364 | | /// This constructor creates `'static` payloads. |
365 | | /// |
366 | | /// # Examples |
367 | | /// |
368 | | /// ``` |
369 | | /// use icu_provider::hello_world::*; |
370 | | /// use icu_provider::prelude::*; |
371 | | /// use std::borrow::Cow; |
372 | | /// |
373 | | /// let local_struct = HelloWorld { |
374 | | /// message: Cow::Owned("example".to_owned()), |
375 | | /// }; |
376 | | /// |
377 | | /// let payload = DataPayload::<HelloWorldV1>::from_owned(local_struct.clone()); |
378 | | /// |
379 | | /// assert_eq!(payload.get(), &local_struct); |
380 | | /// ``` |
381 | | #[inline] |
382 | 0 | pub fn from_owned(data: M::DataStruct) -> Self { |
383 | 0 | Self(DataPayloadInner::Yoke( |
384 | 0 | Yoke::new_owned(data).convert_cart_into_option_pointer(), |
385 | 0 | )) |
386 | 0 | } Unexecuted instantiation: <icu_provider::response::DataPayload<icu_provider::marker_full::ErasedMarker<icu_properties::provider::PropertyUnicodeSet>>>::from_owned Unexecuted instantiation: <icu_provider::response::DataPayload<icu_provider::marker_full::ErasedMarker<icu_properties::provider::PropertyCodePointSet>>>::from_owned Unexecuted instantiation: <icu_provider::response::DataPayload<_>>::from_owned |
387 | | |
388 | | /// Construct a [`DataPayload`] from a static reference. |
389 | | /// |
390 | | /// This is mainly used by databake. |
391 | | #[inline] |
392 | 0 | pub const fn from_static_ref(data: &'static M::DataStruct) -> Self { |
393 | 0 | Self(DataPayloadInner::StaticRef(data)) |
394 | 0 | } Unexecuted instantiation: <icu_provider::response::DataPayload<icu_provider::marker_full::ErasedMarker<icu_properties::provider::PropertyUnicodeSet>>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_provider::marker_full::ErasedMarker<icu_properties::provider::PropertyCodePointSet>>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryDashV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryMathV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumScriptV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryAlnumV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryBlankV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryCasedV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryEmojiV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryGraphV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryPrintV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryHyphenV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryXdigitV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryIdStartV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryRadicalV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumBidiClassV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumLineBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumWordBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryExtenderV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryHexDigitV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryNfcInertV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryNfdInertV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryXidStartV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryDiacriticV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryLowercaseV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryNfkcInertV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryNfkdInertV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryUppercaseV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumJoiningTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumNumericTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryAlphabeticV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryBasicEmojiV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryDeprecatedV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryIdContinueV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinarySoftDottedV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryWhiteSpaceV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumJoiningGroupV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryBidiControlV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryIdeographicV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryJoinControlV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryXidContinueV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumSentenceBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryBidiMirroredV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryGraphemeBaseV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryGraphemeLinkV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumEastAsianWidthV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryAsciiHexDigitV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryCaseIgnorableV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryCaseSensitiveV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryEmojiModifierV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryPatternSyntaxV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryQuotationMarkV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumGeneralCategoryV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryEmojiComponentV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryGraphemeExtendV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinarySegmentStarterV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyScriptWithExtensionsV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryIdsUnaryOperatorV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinarySentenceTerminalV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryUnifiedIdeographV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumBidiMirroringGlyphV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumHangulSyllableTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumIndicConjunctBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryEmojiModifierBaseV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryEmojiPresentationV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryIdCompatMathStartV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryIdsBinaryOperatorV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryPatternWhiteSpaceV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryRegionalIndicatorV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryVariationSelectorV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumVerticalOrientationV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryIdsTrinaryOperatorV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumGraphemeClusterBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryTerminalPunctuationV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumIndicSyllabicCategoryV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryExtendedPictographicV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryIdCompatMathContinueV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryChangesWhenCasefoldedV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryChangesWhenCasemappedV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryChangesWhenLowercasedV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryChangesWhenTitlecasedV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryChangesWhenUppercasedV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryLogicalOrderExceptionV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryModifierCombiningMarkV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryNoncharacterCodePointV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyEnumCanonicalCombiningClassV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryFullCompositionExclusionV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryChangesWhenNfkcCasefoldedV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryDefaultIgnorableCodePointV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::PropertyBinaryPrependedConcatenationMarkV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongScriptV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseScriptV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortScriptV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongBidiClassV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongLineBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongWordBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseBidiClassV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseLineBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseWordBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortBidiClassV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortLineBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortWordBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongJoiningTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongNumericTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongJoiningGroupV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseJoiningTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseNumericTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortJoiningTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortNumericTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongSentenceBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseJoiningGroupV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortJoiningGroupV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongEastAsianWidthV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseSentenceBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortSentenceBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongGeneralCategoryV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseEastAsianWidthV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortEastAsianWidthV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseGeneralCategoryV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortGeneralCategoryV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongHangulSyllableTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongIndicConjunctBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongVerticalOrientationV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseHangulSyllableTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseIndicConjunctBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortHangulSyllableTypeV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortIndicConjunctBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongGraphemeClusterBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseGeneralCategoryMaskV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseVerticalOrientationV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortVerticalOrientationV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameLongIndicSyllabicCategoryV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseGraphemeClusterBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortGraphemeClusterBreakV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseIndicSyllabicCategoryV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameShortIndicSyllabicCategoryV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_properties::provider::names::PropertyNameParseCanonicalCombiningClassV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerNfcV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerNfdDataV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerNfkdDataV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerNfdTablesV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerUts46DataV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerNfkdTablesV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerNfdSupplementV1>>::from_static_ref Unexecuted instantiation: <icu_provider::response::DataPayload<_>>::from_static_ref |
395 | | |
396 | | /// Mutate the data contained in this [`DataPayload`]. |
397 | | /// |
398 | | /// For safety, all mutation operations must take place within a helper function that cannot |
399 | | /// borrow data from the surrounding context. |
400 | | /// |
401 | | /// # Examples |
402 | | /// |
403 | | /// Basic usage: |
404 | | /// |
405 | | /// ``` |
406 | | /// use icu_provider::hello_world::HelloWorldV1; |
407 | | /// use icu_provider::prelude::*; |
408 | | /// |
409 | | /// let mut payload = DataPayload::<HelloWorldV1>::from_static_str("Hello"); |
410 | | /// |
411 | | /// payload.with_mut(|s| s.message.to_mut().push_str(" World")); |
412 | | /// |
413 | | /// assert_eq!("Hello World", payload.get().message); |
414 | | /// ``` |
415 | | /// |
416 | | /// To transfer data from the context into the data struct, use the `move` keyword: |
417 | | /// |
418 | | /// ``` |
419 | | /// use icu_provider::hello_world::HelloWorldV1; |
420 | | /// use icu_provider::prelude::*; |
421 | | /// |
422 | | /// let mut payload = DataPayload::<HelloWorldV1>::from_static_str("Hello"); |
423 | | /// |
424 | | /// let suffix = " World"; |
425 | | /// payload.with_mut(move |s| s.message.to_mut().push_str(suffix)); |
426 | | /// |
427 | | /// assert_eq!("Hello World", payload.get().message); |
428 | | /// ``` |
429 | 0 | pub fn with_mut<'a, F>(&'a mut self, f: F) |
430 | 0 | where |
431 | 0 | F: 'static + for<'b> FnOnce(&'b mut <M::DataStruct as Yokeable<'a>>::Output), |
432 | 0 | M::DataStruct: zerofrom::ZeroFrom<'static, M::DataStruct>, |
433 | | { |
434 | 0 | if let DataPayloadInner::StaticRef(r) = self.0 { |
435 | 0 | self.0 = DataPayloadInner::Yoke( |
436 | 0 | Yoke::new_owned(zerofrom::ZeroFrom::zero_from(r)) |
437 | 0 | .convert_cart_into_option_pointer(), |
438 | 0 | ); |
439 | 0 | } |
440 | 0 | match &mut self.0 { |
441 | 0 | DataPayloadInner::Yoke(yoke) => yoke.with_mut(f), |
442 | 0 | _ => unreachable!(), |
443 | | } |
444 | 0 | } |
445 | | |
446 | | /// Borrows the underlying data. |
447 | | /// |
448 | | /// This function should be used like [`Deref`] would normally be used. For more information on |
449 | | /// why [`DataPayload`] cannot implement [`Deref`], see the `yoke` crate. |
450 | | /// |
451 | | /// # Examples |
452 | | /// |
453 | | /// ``` |
454 | | /// use icu_provider::hello_world::HelloWorldV1; |
455 | | /// use icu_provider::prelude::*; |
456 | | /// |
457 | | /// let payload = DataPayload::<HelloWorldV1>::from_static_str("Demo"); |
458 | | /// |
459 | | /// assert_eq!("Demo", payload.get().message); |
460 | | /// ``` |
461 | | #[inline] |
462 | 0 | pub fn get<'a>(&'a self) -> &'a <M::DataStruct as Yokeable<'a>>::Output { |
463 | 0 | match &self.0 { |
464 | 0 | DataPayloadInner::Yoke(yoke) => yoke.get(), |
465 | 0 | DataPayloadInner::StaticRef(r) => Yokeable::transform(*r), |
466 | | } |
467 | 0 | } Unexecuted instantiation: <icu_provider::response::DataPayload<icu_provider::marker_full::ErasedMarker<icu_properties::provider::PropertyUnicodeSet>>>::get Unexecuted instantiation: <icu_provider::response::DataPayload<icu_provider::marker_full::ErasedMarker<icu_properties::provider::PropertyCodePointSet>>>::get Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerNfcV1>>::get Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerNfdDataV1>>::get Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerNfdTablesV1>>::get Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerNfkdTablesV1>>::get Unexecuted instantiation: <icu_provider::response::DataPayload<icu_normalizer::provider::NormalizerNfdSupplementV1>>::get Unexecuted instantiation: <icu_provider::response::DataPayload<_>>::get |
468 | | |
469 | | /// Borrows the underlying data statically if possible. |
470 | | /// |
471 | | /// This will succeed if [`DataPayload`] is constructed with [`DataPayload::from_static_ref`], which is used by |
472 | | /// baked providers. |
473 | | #[inline] |
474 | 0 | pub fn get_static(&self) -> Option<&'static <M::DataStruct as Yokeable<'static>>::Output> { |
475 | 0 | match &self.0 { |
476 | 0 | DataPayloadInner::Yoke(_) => None, |
477 | 0 | DataPayloadInner::StaticRef(r) => Some(Yokeable::transform(*r)), |
478 | | } |
479 | 0 | } |
480 | | |
481 | | /// Maps `DataPayload<M>` to `DataPayload<M2>` by projecting it with [`Yoke::map_project`]. |
482 | | /// |
483 | | /// This is accomplished by a function that takes `M`'s data type and returns `M2`'s data |
484 | | /// type. The function takes a second argument which should be ignored. For more details, |
485 | | /// see [`Yoke::map_project()`]. |
486 | | /// |
487 | | /// The standard [`DataPayload::map_project()`] function moves `self` and cannot capture any |
488 | | /// data from its context. Use one of the sister methods if you need these capabilities: |
489 | | /// |
490 | | /// - [`DataPayload::map_project_cloned()`] if you don't have ownership of `self` |
491 | | /// - [`DataPayload::try_map_project()`] to bubble up an error |
492 | | /// - [`DataPayload::try_map_project_cloned()`] to do both of the above |
493 | | /// |
494 | | /// # Examples |
495 | | /// |
496 | | /// Map from `HelloWorld` to a `Cow<str>` containing just the message: |
497 | | /// |
498 | | /// ``` |
499 | | /// use icu_provider::hello_world::*; |
500 | | /// use icu_provider::prelude::*; |
501 | | /// use std::borrow::Cow; |
502 | | /// |
503 | | /// // A custom marker type is required when using `map_project`. The DataStruct should be the |
504 | | /// // target type, and the Cart should correspond to the type being transformed. |
505 | | /// |
506 | | /// struct HelloWorldV1MessageMarker; |
507 | | /// impl DynamicDataMarker for HelloWorldV1MessageMarker { |
508 | | /// type DataStruct = Cow<'static, str>; |
509 | | /// } |
510 | | /// |
511 | | /// let p1: DataPayload<HelloWorldV1> = DataPayload::from_owned(HelloWorld { |
512 | | /// message: Cow::Borrowed("Hello World"), |
513 | | /// }); |
514 | | /// |
515 | | /// assert_eq!("Hello World", p1.get().message); |
516 | | /// |
517 | | /// let p2: DataPayload<HelloWorldV1MessageMarker> = p1.map_project(|obj, _| obj.message); |
518 | | /// |
519 | | /// // Note: at this point, p1 has been moved. |
520 | | /// assert_eq!("Hello World", p2.get()); |
521 | | /// ``` |
522 | 0 | pub fn map_project<M2, F>(self, f: F) -> DataPayload<M2> |
523 | 0 | where |
524 | 0 | M2: DynamicDataMarker, |
525 | 0 | F: for<'a> FnOnce( |
526 | 0 | <M::DataStruct as Yokeable<'a>>::Output, |
527 | 0 | PhantomData<&'a ()>, |
528 | 0 | ) -> <M2::DataStruct as Yokeable<'a>>::Output, |
529 | 0 | M::DataStruct: zerofrom::ZeroFrom<'static, M::DataStruct>, |
530 | | { |
531 | | DataPayload(DataPayloadInner::Yoke( |
532 | 0 | match self.0 { |
533 | 0 | DataPayloadInner::Yoke(yoke) => yoke, |
534 | 0 | DataPayloadInner::StaticRef(r) => Yoke::new_owned(zerofrom::ZeroFrom::zero_from(r)) |
535 | 0 | .convert_cart_into_option_pointer(), |
536 | | } |
537 | 0 | .map_project(f), |
538 | | )) |
539 | 0 | } |
540 | | |
541 | | /// Version of [`DataPayload::map_project()`] that borrows `self` instead of moving `self`. |
542 | | /// |
543 | | /// # Examples |
544 | | /// |
545 | | /// Same example as above, but this time, do not move out of `p1`: |
546 | | /// |
547 | | /// ``` |
548 | | /// // Same imports and definitions as above |
549 | | /// # use icu_provider::hello_world::*; |
550 | | /// # use icu_provider::prelude::*; |
551 | | /// # use std::borrow::Cow; |
552 | | /// # struct HelloWorldV1MessageMarker; |
553 | | /// # impl DynamicDataMarker for HelloWorldV1MessageMarker { |
554 | | /// # type DataStruct = Cow<'static, str>; |
555 | | /// # } |
556 | | /// |
557 | | /// let p1: DataPayload<HelloWorldV1> = DataPayload::from_owned(HelloWorld { |
558 | | /// message: Cow::Borrowed("Hello World"), |
559 | | /// }); |
560 | | /// |
561 | | /// assert_eq!("Hello World", p1.get().message); |
562 | | /// |
563 | | /// let p2: DataPayload<HelloWorldV1MessageMarker> = |
564 | | /// p1.map_project_cloned(|obj, _| obj.message.clone()); |
565 | | /// |
566 | | /// // Note: p1 is still valid. |
567 | | /// assert_eq!(p1.get().message, *p2.get()); |
568 | | /// ``` |
569 | 0 | pub fn map_project_cloned<'this, M2, F>(&'this self, f: F) -> DataPayload<M2> |
570 | 0 | where |
571 | 0 | M2: DynamicDataMarker, |
572 | 0 | F: for<'a> FnOnce( |
573 | 0 | &'this <M::DataStruct as Yokeable<'a>>::Output, |
574 | 0 | PhantomData<&'a ()>, |
575 | 0 | ) -> <M2::DataStruct as Yokeable<'a>>::Output, |
576 | | { |
577 | 0 | DataPayload(DataPayloadInner::Yoke(match &self.0 { |
578 | 0 | DataPayloadInner::Yoke(yoke) => yoke.map_project_cloned(f), |
579 | 0 | DataPayloadInner::StaticRef(r) => { |
580 | 0 | let output: <M2::DataStruct as Yokeable<'static>>::Output = |
581 | 0 | f(Yokeable::transform(*r), PhantomData); |
582 | | // Safety: <M2::Yokeable as Yokeable<'static>>::Output is the same type as M2::Yokeable; |
583 | | // we're going from 'static to 'static, however in a generic context it's not |
584 | | // clear to the compiler that that is the case. We have to use the unsafe make API to do this. |
585 | 0 | let yokeable: M2::DataStruct = unsafe { M2::DataStruct::make(output) }; |
586 | 0 | Yoke::new_owned(yokeable).convert_cart_into_option_pointer() |
587 | | } |
588 | | })) |
589 | 0 | } |
590 | | |
591 | | /// Version of [`DataPayload::map_project()`] that bubbles up an error from `f`. |
592 | | /// |
593 | | /// # Examples |
594 | | /// |
595 | | /// Same example as above, but bubble up an error: |
596 | | /// |
597 | | /// ``` |
598 | | /// // Same imports and definitions as above |
599 | | /// # use icu_provider::hello_world::*; |
600 | | /// # use icu_provider::prelude::*; |
601 | | /// # use std::borrow::Cow; |
602 | | /// # struct HelloWorldV1MessageMarker; |
603 | | /// # impl DynamicDataMarker for HelloWorldV1MessageMarker { |
604 | | /// # type DataStruct = Cow<'static, str>; |
605 | | /// # } |
606 | | /// |
607 | | /// let p1: DataPayload<HelloWorldV1> = DataPayload::from_owned(HelloWorld { |
608 | | /// message: Cow::Borrowed("Hello World"), |
609 | | /// }); |
610 | | /// |
611 | | /// assert_eq!("Hello World", p1.get().message); |
612 | | /// |
613 | | /// let string_to_append = "Extra"; |
614 | | /// let p2: DataPayload<HelloWorldV1MessageMarker> = |
615 | | /// p1.try_map_project(|mut obj, _| { |
616 | | /// if obj.message.is_empty() { |
617 | | /// return Err("Example error"); |
618 | | /// } |
619 | | /// obj.message.to_mut().push_str(string_to_append); |
620 | | /// Ok(obj.message) |
621 | | /// })?; |
622 | | /// |
623 | | /// assert_eq!("Hello WorldExtra", p2.get()); |
624 | | /// # Ok::<(), &'static str>(()) |
625 | | /// ``` |
626 | 0 | pub fn try_map_project<M2, F, E>(self, f: F) -> Result<DataPayload<M2>, E> |
627 | 0 | where |
628 | 0 | M2: DynamicDataMarker, |
629 | 0 | F: for<'a> FnOnce( |
630 | 0 | <M::DataStruct as Yokeable<'a>>::Output, |
631 | 0 | PhantomData<&'a ()>, |
632 | 0 | ) -> Result<<M2::DataStruct as Yokeable<'a>>::Output, E>, |
633 | 0 | M::DataStruct: zerofrom::ZeroFrom<'static, M::DataStruct>, |
634 | | { |
635 | | Ok(DataPayload(DataPayloadInner::Yoke( |
636 | 0 | match self.0 { |
637 | 0 | DataPayloadInner::Yoke(yoke) => yoke, |
638 | 0 | DataPayloadInner::StaticRef(r) => Yoke::new_owned(zerofrom::ZeroFrom::zero_from(r)) |
639 | 0 | .convert_cart_into_option_pointer(), |
640 | | } |
641 | 0 | .try_map_project(f)?, |
642 | | ))) |
643 | 0 | } |
644 | | |
645 | | /// Version of [`DataPayload::map_project_cloned()`] that bubbles up an error from `f`. |
646 | | /// |
647 | | /// # Examples |
648 | | /// |
649 | | /// Same example as above, but bubble up an error: |
650 | | /// |
651 | | /// ``` |
652 | | /// // Same imports and definitions as above |
653 | | /// # use icu_provider::hello_world::*; |
654 | | /// # use icu_provider::prelude::*; |
655 | | /// # use std::borrow::Cow; |
656 | | /// # struct HelloWorldV1MessageMarker; |
657 | | /// # impl DynamicDataMarker for HelloWorldV1MessageMarker { |
658 | | /// # type DataStruct = Cow<'static, str>; |
659 | | /// # } |
660 | | /// |
661 | | /// let p1: DataPayload<HelloWorldV1> = DataPayload::from_owned(HelloWorld { |
662 | | /// message: Cow::Borrowed("Hello World"), |
663 | | /// }); |
664 | | /// |
665 | | /// assert_eq!("Hello World", p1.get().message); |
666 | | /// |
667 | | /// let string_to_append = "Extra"; |
668 | | /// let p2: DataPayload<HelloWorldV1MessageMarker> = p1 |
669 | | /// .try_map_project_cloned(|obj, _| { |
670 | | /// if obj.message.is_empty() { |
671 | | /// return Err("Example error"); |
672 | | /// } |
673 | | /// let mut message = obj.message.clone(); |
674 | | /// message.to_mut().push_str(string_to_append); |
675 | | /// Ok(message) |
676 | | /// })?; |
677 | | /// |
678 | | /// // Note: p1 is still valid, but the values no longer equal. |
679 | | /// assert_ne!(p1.get().message, *p2.get()); |
680 | | /// assert_eq!("Hello WorldExtra", p2.get()); |
681 | | /// # Ok::<(), &'static str>(()) |
682 | | /// ``` |
683 | 0 | pub fn try_map_project_cloned<'this, M2, F, E>(&'this self, f: F) -> Result<DataPayload<M2>, E> |
684 | 0 | where |
685 | 0 | M2: DynamicDataMarker, |
686 | 0 | F: for<'a> FnOnce( |
687 | 0 | &'this <M::DataStruct as Yokeable<'a>>::Output, |
688 | 0 | PhantomData<&'a ()>, |
689 | 0 | ) -> Result<<M2::DataStruct as Yokeable<'a>>::Output, E>, |
690 | | { |
691 | 0 | Ok(DataPayload(DataPayloadInner::Yoke(match &self.0 { |
692 | 0 | DataPayloadInner::Yoke(yoke) => yoke.try_map_project_cloned(f)?, |
693 | 0 | DataPayloadInner::StaticRef(r) => { |
694 | 0 | let output: <M2::DataStruct as Yokeable<'static>>::Output = |
695 | 0 | f(Yokeable::transform(*r), PhantomData)?; |
696 | | // Safety: <M2::Yokeable as Yokeable<'static>>::Output is the same type as M2::Yokeable, |
697 | | // and `output` is `'static` so there are no lifetimes to manage for `make()` |
698 | 0 | Yoke::new_owned(unsafe { M2::DataStruct::make(output) }) |
699 | 0 | .convert_cart_into_option_pointer() |
700 | | } |
701 | | }))) |
702 | 0 | } |
703 | | |
704 | | /// Convert between two [`DynamicDataMarker`] types that are compatible with each other |
705 | | /// with compile-time type checking. |
706 | | /// |
707 | | /// This happens if they both have the same [`DynamicDataMarker::DataStruct`] type. |
708 | | /// |
709 | | /// Can be used to erase the marker of a data payload in cases where multiple markers correspond |
710 | | /// to the same data struct. |
711 | | /// |
712 | | /// For runtime dynamic casting, use [`DataPayload::dynamic_cast_mut()`]. |
713 | | /// |
714 | | /// # Examples |
715 | | /// |
716 | | /// ```no_run |
717 | | /// use icu_provider::hello_world::*; |
718 | | /// use icu_provider::prelude::*; |
719 | | /// |
720 | | /// struct CustomHelloWorldV1; |
721 | | /// impl DynamicDataMarker for CustomHelloWorldV1 { |
722 | | /// type DataStruct = HelloWorld<'static>; |
723 | | /// } |
724 | | /// |
725 | | /// let hello_world: DataPayload<HelloWorldV1> = todo!(); |
726 | | /// let custom: DataPayload<CustomHelloWorldV1> = hello_world.cast(); |
727 | | /// ``` |
728 | | #[inline] |
729 | 0 | pub fn cast<M2>(self) -> DataPayload<M2> |
730 | 0 | where |
731 | 0 | M2: DynamicDataMarker<DataStruct = M::DataStruct>, |
732 | | { |
733 | 0 | DataPayload(match self.0 { |
734 | 0 | DataPayloadInner::Yoke(yoke) => DataPayloadInner::Yoke(yoke), |
735 | 0 | DataPayloadInner::StaticRef(r) => DataPayloadInner::StaticRef(r), |
736 | | }) |
737 | 0 | } Unexecuted instantiation: <icu_provider::response::DataPayload<icu_provider::marker_full::ErasedMarker<icu_properties::provider::PropertyUnicodeSet>>>::cast::<icu_provider::marker_full::ErasedMarker<icu_properties::provider::PropertyUnicodeSet>> Unexecuted instantiation: <icu_provider::response::DataPayload<icu_provider::marker_full::ErasedMarker<icu_properties::provider::PropertyCodePointSet>>>::cast::<icu_provider::marker_full::ErasedMarker<icu_properties::provider::PropertyCodePointSet>> Unexecuted instantiation: <icu_provider::response::DataPayload<_>>::cast::<_> |
738 | | |
739 | | /// Convert between two [`DynamicDataMarker`] types that are compatible with each other |
740 | | /// with compile-time type checking. |
741 | | /// |
742 | | /// This happens if they both have the same [`DynamicDataMarker::DataStruct`] type. |
743 | | /// |
744 | | /// Can be used to erase the marker of a data payload in cases where multiple markers correspond |
745 | | /// to the same data struct. |
746 | | #[inline] |
747 | 0 | pub fn cast_ref<M2>(&self) -> &DataPayload<M2> |
748 | 0 | where |
749 | 0 | M2: DynamicDataMarker<DataStruct = M::DataStruct>, |
750 | | { |
751 | | // SAFETY: As seen in the implementation of `cast`, the struct is the same, it's just the generic that changes. |
752 | 0 | unsafe { &*(self as *const DataPayload<M> as *const DataPayload<M2>) } |
753 | 0 | } |
754 | | |
755 | | /// Convert a [`DataPayload`] to one of the same type with runtime type checking. |
756 | | /// |
757 | | /// Primarily useful to convert from a generic to a concrete marker type. |
758 | | /// |
759 | | /// If the `M2` type argument does not match the true marker type, a `DataError` is returned. |
760 | | /// |
761 | | /// For compile-time static casting, use [`DataPayload::cast()`]. |
762 | | /// |
763 | | /// # Examples |
764 | | /// |
765 | | /// Short-circuit a data request request based on the marker, returning |
766 | | /// a result from a different data provider: |
767 | | /// |
768 | | /// ``` |
769 | | /// use core::any::TypeId; |
770 | | /// use icu_locale_core::locale; |
771 | | /// use icu_provider::hello_world::*; |
772 | | /// use icu_provider::prelude::*; |
773 | | /// use icu_provider_adapters::empty::EmptyDataProvider; |
774 | | /// use std::borrow::Cow; |
775 | | /// |
776 | | /// struct MyForkingProvider<P0, P1> { |
777 | | /// fallback_provider: P0, |
778 | | /// hello_world_provider: P1, |
779 | | /// } |
780 | | /// |
781 | | /// impl<M, P0, P1> DataProvider<M> for MyForkingProvider<P0, P1> |
782 | | /// where |
783 | | /// M: DataMarker, |
784 | | /// P0: DataProvider<M>, |
785 | | /// P1: DataProvider<HelloWorldV1>, |
786 | | /// { |
787 | | /// #[inline] |
788 | | /// fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> { |
789 | | /// if TypeId::of::<HelloWorldV1>() == TypeId::of::<M>() { |
790 | | /// let response = DataProvider::<HelloWorldV1>::load( |
791 | | /// &self.hello_world_provider, |
792 | | /// req, |
793 | | /// )?; |
794 | | /// Ok(DataResponse { |
795 | | /// metadata: response.metadata, |
796 | | /// payload: response.payload.dynamic_cast()?, |
797 | | /// }) |
798 | | /// } else { |
799 | | /// self.fallback_provider.load(req) |
800 | | /// } |
801 | | /// } |
802 | | /// } |
803 | | /// |
804 | | /// let provider = MyForkingProvider { |
805 | | /// fallback_provider: EmptyDataProvider::new(), |
806 | | /// hello_world_provider: HelloWorldProvider, |
807 | | /// }; |
808 | | /// |
809 | | /// let formatter = |
810 | | /// HelloWorldFormatter::try_new_unstable(&provider, locale!("de").into()) |
811 | | /// .unwrap(); |
812 | | /// |
813 | | /// // This succeeds because the data was loaded from HelloWorldProvider |
814 | | /// // rather than the empty fallback provider. |
815 | | /// assert_eq!(formatter.format_to_string(), "Hallo Welt"); |
816 | | /// ``` |
817 | 0 | pub fn dynamic_cast<M2>(self) -> Result<DataPayload<M2>, DataError> |
818 | 0 | where |
819 | 0 | M2: DynamicDataMarker, |
820 | | { |
821 | 0 | let mut option_self = Some(self); |
822 | 0 | let mut option_out = None::<DataPayload<M2>>; |
823 | 0 | if let Some(x) = (&mut option_out as &mut dyn core::any::Any).downcast_mut() { |
824 | 0 | core::mem::swap(&mut option_self, x); |
825 | 0 | debug_assert!(option_out.is_some()); |
826 | 0 | if let Some(out) = option_out { |
827 | 0 | return Ok(out); |
828 | 0 | } |
829 | 0 | } |
830 | 0 | Err(DataError::for_type::<M2>().with_str_context(core::any::type_name::<M>())) |
831 | 0 | } |
832 | | |
833 | | /// Convert a mutable reference of a [`DataPayload`] to another mutable reference |
834 | | /// of the same type with runtime type checking. |
835 | | /// |
836 | | /// Primarily useful to convert from a generic to a concrete marker type. |
837 | | /// |
838 | | /// If the `M2` type argument does not match the true marker type, a `DataError` is returned. |
839 | | /// |
840 | | /// For compile-time static casting, use [`DataPayload::cast()`]. |
841 | | /// |
842 | | /// # Examples |
843 | | /// |
844 | | /// Change the results of a particular request based on marker: |
845 | | /// |
846 | | /// ``` |
847 | | /// use icu_locale_core::locale; |
848 | | /// use icu_provider::hello_world::*; |
849 | | /// use icu_provider::prelude::*; |
850 | | /// |
851 | | /// struct MyWrapper<P> { |
852 | | /// inner: P, |
853 | | /// } |
854 | | /// |
855 | | /// impl<M, P> DataProvider<M> for MyWrapper<P> |
856 | | /// where |
857 | | /// M: DataMarker, |
858 | | /// P: DataProvider<M>, |
859 | | /// { |
860 | | /// #[inline] |
861 | | /// fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> { |
862 | | /// let mut res = self.inner.load(req)?; |
863 | | /// let mut cast_result = |
864 | | /// res.payload.dynamic_cast_mut::<HelloWorldV1>(); |
865 | | /// if let Ok(ref mut concrete_payload) = cast_result { |
866 | | /// // Add an emoji to the hello world message |
867 | | /// concrete_payload.with_mut(|data| { |
868 | | /// data.message.to_mut().insert_str(0, "✨ "); |
869 | | /// }); |
870 | | /// } |
871 | | /// Ok(res) |
872 | | /// } |
873 | | /// } |
874 | | /// |
875 | | /// let provider = MyWrapper { |
876 | | /// inner: HelloWorldProvider, |
877 | | /// }; |
878 | | /// let formatter = |
879 | | /// HelloWorldFormatter::try_new_unstable(&provider, locale!("de").into()) |
880 | | /// .unwrap(); |
881 | | /// |
882 | | /// assert_eq!(formatter.format_to_string(), "✨ Hallo Welt"); |
883 | | /// ``` |
884 | | #[inline] |
885 | 0 | pub fn dynamic_cast_mut<M2>(&mut self) -> Result<&mut DataPayload<M2>, DataError> |
886 | 0 | where |
887 | 0 | M2: DynamicDataMarker, |
888 | | { |
889 | 0 | let this: &mut dyn core::any::Any = self; |
890 | 0 | if let Some(this) = this.downcast_mut() { |
891 | 0 | Ok(this) |
892 | | } else { |
893 | 0 | Err(DataError::for_type::<M2>().with_str_context(core::any::type_name::<M>())) |
894 | | } |
895 | 0 | } |
896 | | } |
897 | | |
898 | | impl DataPayload<BufferMarker> { |
899 | | /// Converts an owned byte buffer into a `DataPayload<BufferMarker>`. |
900 | | /// |
901 | | /// ✨ *Enabled with the `alloc` Cargo feature.* |
902 | | #[cfg(feature = "alloc")] |
903 | | pub fn from_owned_buffer(buffer: Box<[u8]>) -> Self { |
904 | | let yoke = Yoke::attach_to_cart(SelectedRc::new(buffer), |b| &**b) |
905 | | .wrap_cart_in_option() |
906 | | .convert_cart_into_option_pointer(); |
907 | | Self(DataPayloadInner::Yoke(yoke)) |
908 | | } |
909 | | |
910 | | /// Converts a yoked byte buffer into a `DataPayload<BufferMarker>`. |
911 | 0 | pub fn from_yoked_buffer(yoke: Yoke<&'static [u8], Option<Cart>>) -> Self { |
912 | 0 | let yoke = Cart::unwrap_cart(yoke); |
913 | 0 | Self(DataPayloadInner::Yoke( |
914 | 0 | yoke.convert_cart_into_option_pointer(), |
915 | 0 | )) |
916 | 0 | } |
917 | | |
918 | | /// Converts a static byte buffer into a `DataPayload<BufferMarker>`. |
919 | 0 | pub fn from_static_buffer(buffer: &'static [u8]) -> Self { |
920 | 0 | Self(DataPayloadInner::Yoke( |
921 | 0 | Yoke::new_owned(buffer).convert_cart_into_option_pointer(), |
922 | 0 | )) |
923 | 0 | } |
924 | | } |
925 | | |
926 | | impl<M> Default for DataPayload<M> |
927 | | where |
928 | | M: DynamicDataMarker, |
929 | | M::DataStruct: Default, |
930 | | { |
931 | 0 | fn default() -> Self { |
932 | 0 | Self::from_owned(Default::default()) |
933 | 0 | } |
934 | | } |
935 | | |
936 | | impl<M, O> DataPayloadOr<M, O> |
937 | | where |
938 | | M: DynamicDataMarker, |
939 | | { |
940 | | /// Creates a [`DataPayloadOr`] from a [`DataPayload`]. |
941 | | #[inline] |
942 | 0 | pub fn from_payload(payload: DataPayload<M>) -> Self { |
943 | 0 | match payload.0 { |
944 | 0 | DataPayloadInner::Yoke(yoke) => Self(DataPayloadOrInner::Yoke(yoke)), |
945 | 0 | DataPayloadInner::StaticRef(r) => Self(DataPayloadOrInner::Inner( |
946 | 0 | DataPayloadOrInnerInner::StaticRef(r), |
947 | 0 | )), |
948 | | } |
949 | 0 | } |
950 | | |
951 | | /// Creates a [`DataPayloadOr`] from the other type `O`. |
952 | | #[inline] |
953 | 0 | pub fn from_other(other: O) -> Self { |
954 | 0 | Self(DataPayloadOrInner::Inner(DataPayloadOrInnerInner::Other( |
955 | 0 | other, |
956 | 0 | ))) |
957 | 0 | } |
958 | | |
959 | | /// Returns whether this object represents a [`DataPayload`]. |
960 | | #[inline] |
961 | 0 | pub fn is_payload(&self) -> bool { |
962 | 0 | match &self.0 { |
963 | 0 | DataPayloadOrInner::Yoke(_) => true, |
964 | 0 | DataPayloadOrInner::Inner(DataPayloadOrInnerInner::StaticRef(_)) => true, |
965 | 0 | DataPayloadOrInner::Inner(DataPayloadOrInnerInner::Other(_)) => false, |
966 | | } |
967 | 0 | } |
968 | | |
969 | | /// Gets the value from this [`DataPayload`] as `Ok` or the other type as `Err`. |
970 | | #[inline] |
971 | 0 | pub fn get<'a>(&'a self) -> Result<&'a <M::DataStruct as Yokeable<'a>>::Output, &'a O> { |
972 | 0 | match &self.0 { |
973 | 0 | DataPayloadOrInner::Yoke(yoke) => Ok(yoke.get()), |
974 | 0 | DataPayloadOrInner::Inner(DataPayloadOrInnerInner::StaticRef(r)) => { |
975 | 0 | Ok(Yokeable::transform(*r)) |
976 | | } |
977 | 0 | DataPayloadOrInner::Inner(DataPayloadOrInnerInner::Other(o)) => Err(o), |
978 | | } |
979 | 0 | } |
980 | | |
981 | | /// Consumes this [`DataPayloadOr`], returning either the wrapped |
982 | | /// [`DataPayload`] or the other type. |
983 | | #[inline] |
984 | 0 | pub fn into_inner(self) -> Result<DataPayload<M>, O> { |
985 | 0 | match self.0 { |
986 | 0 | DataPayloadOrInner::Yoke(yoke) => Ok(DataPayload(DataPayloadInner::Yoke(yoke))), |
987 | 0 | DataPayloadOrInner::Inner(DataPayloadOrInnerInner::StaticRef(r)) => { |
988 | 0 | Ok(DataPayload(DataPayloadInner::StaticRef(r))) |
989 | | } |
990 | 0 | DataPayloadOrInner::Inner(DataPayloadOrInnerInner::Other(o)) => Err(o), |
991 | | } |
992 | 0 | } |
993 | | } |
994 | | |
995 | | impl<M> DataPayloadOr<M, ()> |
996 | | where |
997 | | M: DynamicDataMarker, |
998 | | { |
999 | | /// Convenience function to return the other type with value `()` |
1000 | | #[inline] |
1001 | 0 | pub fn none() -> Self { |
1002 | 0 | Self::from_other(()) |
1003 | 0 | } |
1004 | | |
1005 | | /// Convenience function to return `Some` or `None` for other type `()` |
1006 | | #[inline] |
1007 | 0 | pub fn get_option<'a>(&'a self) -> Option<&'a <M::DataStruct as Yokeable<'a>>::Output> { |
1008 | 0 | self.get().ok() |
1009 | 0 | } |
1010 | | } |
1011 | | |
1012 | | /// A response object containing an object as payload and metadata about it. |
1013 | | #[allow(clippy::exhaustive_structs)] // this type is stable |
1014 | | pub struct DataResponse<M> |
1015 | | where |
1016 | | M: DynamicDataMarker, |
1017 | | { |
1018 | | /// Metadata about the returned object. |
1019 | | pub metadata: DataResponseMetadata, |
1020 | | |
1021 | | /// The object itself |
1022 | | pub payload: DataPayload<M>, |
1023 | | } |
1024 | | |
1025 | | impl<M> DataResponse<M> |
1026 | | where |
1027 | | M: DynamicDataMarker, |
1028 | | { |
1029 | | /// Convert between two [`DynamicDataMarker`] types that are compatible with each other |
1030 | | /// with compile-time type checking. |
1031 | | /// |
1032 | | /// This happens if they both have the same [`DynamicDataMarker::DataStruct`] type. |
1033 | | /// |
1034 | | /// Can be used to erase the marker of a data payload in cases where multiple markers correspond |
1035 | | /// to the same data struct. |
1036 | | /// |
1037 | | /// For runtime dynamic casting, use [`DataResponse::dynamic_cast()`]. |
1038 | | #[inline] |
1039 | 0 | pub fn cast<M2>(self) -> DataResponse<M2> |
1040 | 0 | where |
1041 | 0 | M2: DynamicDataMarker<DataStruct = M::DataStruct>, |
1042 | | { |
1043 | 0 | DataResponse { |
1044 | 0 | metadata: self.metadata, |
1045 | 0 | payload: self.payload.cast(), |
1046 | 0 | } |
1047 | 0 | } |
1048 | | |
1049 | | /// Convert a [`DataResponse`] to one of the same type with runtime type checking. |
1050 | | /// |
1051 | | /// Primarily useful to convert from a generic to a concrete marker type. |
1052 | | /// |
1053 | | /// If the `M2` type argument does not match the true marker type, a `DataError` is returned. |
1054 | | /// |
1055 | | /// For compile-time static casting, use [`DataResponse::cast()`]. |
1056 | | #[inline] |
1057 | 0 | pub fn dynamic_cast<M2>(self) -> Result<DataResponse<M2>, DataError> |
1058 | 0 | where |
1059 | 0 | M2: DynamicDataMarker, |
1060 | | { |
1061 | | Ok(DataResponse { |
1062 | 0 | metadata: self.metadata, |
1063 | 0 | payload: self.payload.dynamic_cast()?, |
1064 | | }) |
1065 | 0 | } |
1066 | | } |
1067 | | |
1068 | | impl<M> Debug for DataResponse<M> |
1069 | | where |
1070 | | M: DynamicDataMarker, |
1071 | | for<'a> &'a <M::DataStruct as Yokeable<'a>>::Output: Debug, |
1072 | | { |
1073 | 0 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { |
1074 | 0 | write!( |
1075 | 0 | f, |
1076 | 0 | "DataResponse {{ metadata: {:?}, payload: {:?} }}", |
1077 | | self.metadata, self.payload |
1078 | | ) |
1079 | 0 | } |
1080 | | } |
1081 | | |
1082 | | /// Cloning a [`DataResponse`] is generally a cheap operation. |
1083 | | /// See notes in the `Clone` impl for [`Yoke`]. |
1084 | | /// |
1085 | | /// # Examples |
1086 | | /// |
1087 | | /// ```no_run |
1088 | | /// use icu_provider::hello_world::*; |
1089 | | /// use icu_provider::prelude::*; |
1090 | | /// |
1091 | | /// let resp1: DataResponse<HelloWorldV1> = todo!(); |
1092 | | /// let resp2 = resp1.clone(); |
1093 | | /// ``` |
1094 | | impl<M> Clone for DataResponse<M> |
1095 | | where |
1096 | | M: DynamicDataMarker, |
1097 | | for<'a> <M::DataStruct as Yokeable<'a>>::Output: Clone, |
1098 | | { |
1099 | 0 | fn clone(&self) -> Self { |
1100 | 0 | Self { |
1101 | 0 | metadata: self.metadata.clone(), |
1102 | 0 | payload: self.payload.clone(), |
1103 | 0 | } |
1104 | 0 | } |
1105 | | } |
1106 | | |
1107 | | #[test] |
1108 | | fn test_debug() { |
1109 | | use crate::hello_world::*; |
1110 | | use crate::prelude::*; |
1111 | | let resp = HelloWorldProvider |
1112 | | .load(DataRequest { |
1113 | | id: DataIdentifierBorrowed::for_locale(&icu_locale_core::locale!("en").into()), |
1114 | | ..Default::default() |
1115 | | }) |
1116 | | .unwrap(); |
1117 | | assert_eq!("DataResponse { metadata: DataResponseMetadata { locale: None, buffer_format: None, checksum: Some(1234) }, payload: HelloWorld { message: \"Hello World\" } }", format!("{resp:?}")); |
1118 | | } |