icu_provider_adapters/
any_payload.rs

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//! Data provider always serving the same struct.
6
7use icu_provider::prelude::*;
8use yoke::trait_hack::YokeTraitHack;
9use yoke::Yokeable;
10use zerofrom::ZeroFrom;
11
12/// A data provider that returns clones of a fixed type-erased payload.
13///
14/// [`AnyPayloadProvider`] implements [`AnyProvider`], so it can be used in
15/// `*_with_any_provider` constructors across ICU4X.
16///
17/// # Examples
18///
19/// ```
20/// use icu_provider::hello_world::*;
21/// use icu_provider::prelude::*;
22/// use icu_provider_adapters::any_payload::AnyPayloadProvider;
23/// use std::borrow::Cow;
24/// use writeable::assert_writeable_eq;
25///
26/// let provider =
27///     AnyPayloadProvider::from_static::<HelloWorldV1Marker>(&HelloWorldV1 {
28///         message: Cow::Borrowed("custom hello world"),
29///     });
30///
31/// // Check that it works:
32/// let formatter = HelloWorldFormatter::try_new_with_any_provider(
33///     &provider,
34///     &Default::default(),
35/// )
36/// .expect("key matches");
37/// assert_writeable_eq!(formatter.format(), "custom hello world");
38///
39/// // Requests for invalid keys get MissingDataKey
40/// assert!(matches!(
41///     provider.load_any(icu_provider::data_key!("foo@1"), Default::default()),
42///     Err(DataError {
43///         kind: DataErrorKind::MissingDataKey,
44///         ..
45///     })
46/// ))
47/// ```
48#[derive(Debug)]
49#[allow(clippy::exhaustive_structs)] // this type is stable
50pub struct AnyPayloadProvider {
51    /// The [`DataKey`] for which to provide data. All others will receive a
52    /// [`DataErrorKind::MissingDataKey`].
53    key: DataKey,
54    /// The [`AnyPayload`] to return on matching requests.
55    data: AnyPayload,
56}
57
58impl AnyPayloadProvider {
59    /// Creates an `AnyPayloadProvider` with an owned (allocated) payload of the given data.
60    pub fn from_owned<M: KeyedDataMarker>(data: M::Yokeable) -> Self
61    where
62        M::Yokeable: icu_provider::MaybeSendSync,
63    {
64        Self::from_payload::<M>(DataPayload::from_owned(data))
65    }
66
67    /// Creates an `AnyPayloadProvider` with a statically borrowed payload of the given data.
68    pub fn from_static<M: KeyedDataMarker>(data: &'static M::Yokeable) -> Self {
69        AnyPayloadProvider {
70            key: M::KEY,
71            data: AnyPayload::from_static_ref(data),
72        }
73    }
74
75    /// Creates an `AnyPayloadProvider` from an existing [`DataPayload`].
76    pub fn from_payload<M: KeyedDataMarker>(payload: DataPayload<M>) -> Self
77    where
78        M::Yokeable: icu_provider::MaybeSendSync,
79    {
80        AnyPayloadProvider {
81            key: M::KEY,
82            data: payload.wrap_into_any_payload(),
83        }
84    }
85
86    /// Creates an `AnyPayloadProvider` from an existing [`AnyPayload`].
87    pub fn from_any_payload<M: KeyedDataMarker>(payload: AnyPayload) -> Self {
88        AnyPayloadProvider {
89            key: M::KEY,
90            data: payload,
91        }
92    }
93
94    /// Creates an `AnyPayloadProvider` with the default (allocated) version of the data struct.
95    pub fn new_default<M: KeyedDataMarker>() -> Self
96    where
97        M::Yokeable: Default,
98        M::Yokeable: icu_provider::MaybeSendSync,
99    {
100        Self::from_owned::<M>(M::Yokeable::default())
101    }
102}
103
104impl AnyProvider for AnyPayloadProvider {
105    fn load_any(&self, key: DataKey, _: DataRequest) -> Result<AnyResponse, DataError> {
106        key.match_key(self.key)?;
107        Ok(AnyResponse {
108            metadata: DataResponseMetadata::default(),
109            payload: Some(self.data.clone()),
110        })
111    }
112}
113
114impl<M> DataProvider<M> for AnyPayloadProvider
115where
116    M: KeyedDataMarker,
117    for<'a> YokeTraitHack<<M::Yokeable as Yokeable<'a>>::Output>: Clone,
118    M::Yokeable: ZeroFrom<'static, M::Yokeable>,
119    M::Yokeable: icu_provider::MaybeSendSync,
120{
121    fn load(&self, req: DataRequest) -> Result<DataResponse<M>, DataError> {
122        self.as_downcasting().load(req)
123    }
124}