| 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 | /// &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 |
| 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 | |