Coverage Report

Created: 2026-05-16 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}