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 | |
7 | use icu_provider::prelude::*; |
8 | use yoke::trait_hack::YokeTraitHack; |
9 | use yoke::Yokeable; |
10 | use 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 | /// &icu_locid::Locale::UND.into(), |
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 |
50 | pub 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 | |
58 | impl 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 | |
104 | impl 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 | |
114 | impl<M> DataProvider<M> for AnyPayloadProvider |
115 | where |
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 | } |
125 | |