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