• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //! Utilities for using trait objects with `DataPayload`.
6 
7 /// Trait to allow conversion from `DataPayload<T>` to `DataPayload<S>`.
8 ///
9 /// This trait can be manually implemented in order to enable [`impl_dynamic_data_provider`].
10 pub trait UpcastDataPayload<M>
11 where
12     M: crate::DynamicDataMarker,
13     Self: Sized + crate::DynamicDataMarker,
14 {
15     /// Upcast a `DataPayload<T>` to a `DataPayload<S>` where `T` implements trait `S`.
upcast(other: crate::DataPayload<M>) -> crate::DataPayload<Self>16     fn upcast(other: crate::DataPayload<M>) -> crate::DataPayload<Self>;
17 }
18 
19 /// Implements [`UpcastDataPayload`] from several data markers to a single data marker
20 /// that all share the same [`DynamicDataMarker::DataStruct`].
21 ///
22 /// # Examples
23 ///
24 /// ```
25 /// use icu_provider::prelude::*;
26 /// use std::borrow::Cow;
27 ///
28 /// struct FooV1;
29 /// impl DynamicDataMarker for FooV1 {
30 ///     type DataStruct = Foo<'static>;
31 /// }
32 /// icu_provider::data_marker!(BarV1, Foo<'static>);
33 /// icu_provider::data_marker!(BazV1, Foo<'static>);
34 ///
35 /// #[derive(yoke::Yokeable)]
36 /// pub struct Foo<'data> {
37 ///     message: Cow<'data, str>,
38 /// };
39 ///
40 /// icu_provider::data_struct!(Foo<'_>);
41 ///
42 /// icu_provider::dynutil::impl_casting_upcast!(FooV1, [BarV1, BazV1,]);
43 /// ```
44 ///
45 /// [`DynamicDataMarker::DataStruct`]: crate::DynamicDataMarker::DataStruct
46 #[macro_export]
47 #[doc(hidden)] // macro
48 macro_rules! __impl_casting_upcast {
49     ($dyn_m:path, [ $($struct_m:ident),+, ]) => {
50         $(
51             impl $crate::dynutil::UpcastDataPayload<$struct_m> for $dyn_m {
52                 fn upcast(other: $crate::DataPayload<$struct_m>) -> $crate::DataPayload<$dyn_m> {
53                     other.cast()
54                 }
55             }
56         )+
57     }
58 }
59 #[doc(inline)]
60 pub use __impl_casting_upcast as impl_casting_upcast;
61 
62 /// Implements [`DynamicDataProvider`] for a marker type `S` on a type that already implements
63 /// [`DynamicDataProvider`] or [`DataProvider`] for one or more `M`, where `M` is a concrete type
64 /// that is convertible to `S` via [`UpcastDataPayload`].
65 ///
66 /// ## Wrapping DataProvider
67 ///
68 /// If your type implements [`DataProvider`], pass a list of markers as the second argument.
69 /// This results in a `DynamicDataProvider` that delegates to a specific marker if the marker
70 /// matches or else returns [`DataErrorKind::MarkerNotFound`].
71 ///
72 /// [`DynamicDataProvider`]: crate::DynamicDataProvider
73 /// [`DataProvider`]: crate::DataProvider
74 /// [`DataErrorKind::MarkerNotFound`]: (crate::DataErrorKind::MarkerNotFound)
75 /// [`SerializeMarker`]: (crate::buf::SerializeMarker)
76 #[doc(hidden)] // macro
77 #[macro_export]
78 macro_rules! __impl_dynamic_data_provider {
79     // allow passing in multiple things to do and get dispatched
80     ($provider:ty, $arms:tt, $one:path, $($rest:path),+) => {
81         $crate::dynutil::impl_dynamic_data_provider!(
82             $provider,
83             $arms,
84             $one
85         );
86 
87         $crate::dynutil::impl_dynamic_data_provider!(
88             $provider,
89             $arms,
90             $($rest),+
91         );
92     };
93 
94     ($provider:ty, { $($ident:ident = $marker:path => $struct_m:ty),+, $(_ => $struct_d:ty,)?}, $dyn_m:ty) => {
95         impl $crate::DynamicDataProvider<$dyn_m> for $provider
96         {
97             fn load_data(
98                 &self,
99                 marker: $crate::DataMarkerInfo,
100                 req: $crate::DataRequest,
101             ) -> Result<
102                 $crate::DataResponse<$dyn_m>,
103                 $crate::DataError,
104             > {
105                 match marker.id.hashed() {
106                     $(
107                         h if h == $marker.id.hashed() => {
108                             let result: $crate::DataResponse<$struct_m> =
109                                 $crate::DynamicDataProvider::<$struct_m>::load_data(self, marker, req)?;
110                             Ok($crate::DataResponse {
111                                 metadata: result.metadata,
112                                 payload: $crate::dynutil::UpcastDataPayload::<$struct_m>::upcast(result.payload),
113                             })
114                         }
115                     )+,
116                     $(
117                         _ => {
118                             let result: $crate::DataResponse<$struct_d> =
119                                 $crate::DynamicDataProvider::<$struct_d>::load_data(self, marker, req)?;
120                             Ok($crate::DataResponse {
121                                 metadata: result.metadata,
122                                 payload: $crate::dynutil::UpcastDataPayload::<$struct_d>::upcast(result.payload),
123                             })
124                         }
125                     )?
126                     _ => Err($crate::DataErrorKind::MarkerNotFound.with_req(marker, req))
127                 }
128             }
129         }
130 
131     };
132     ($provider:ty, [ $($(#[$cfg:meta])? $struct_m:ty),+, ], $dyn_m:path) => {
133         impl $crate::DynamicDataProvider<$dyn_m> for $provider
134         {
135             fn load_data(
136                 &self,
137                 marker: $crate::DataMarkerInfo,
138                 req: $crate::DataRequest,
139             ) -> Result<
140                 $crate::DataResponse<$dyn_m>,
141                 $crate::DataError,
142             > {
143                 match marker.id.hashed() {
144                     $(
145                         $(#[$cfg])?
146                         h if h == <$struct_m as $crate::DataMarker>::INFO.id.hashed() => {
147                             let result: $crate::DataResponse<$struct_m> =
148                                 $crate::DataProvider::load(self, req)?;
149                             Ok($crate::DataResponse {
150                                 metadata: result.metadata,
151                                 payload: $crate::dynutil::UpcastDataPayload::<$struct_m>::upcast(result.payload),
152                             })
153                         }
154                     )+,
155                     _ => Err($crate::DataErrorKind::MarkerNotFound.with_req(marker, req))
156                 }
157             }
158         }
159     };
160 }
161 #[doc(inline)]
162 pub use __impl_dynamic_data_provider as impl_dynamic_data_provider;
163 
164 #[doc(hidden)] // macro
165 #[macro_export]
166 macro_rules! __impl_iterable_dynamic_data_provider {
167     ($provider:ty, [ $($(#[$cfg:meta])? $struct_m:ty),+, ], $dyn_m:path) => {
168         impl $crate::IterableDynamicDataProvider<$dyn_m> for $provider {
169             fn iter_ids_for_marker(&self, marker: $crate::DataMarkerInfo) -> Result<alloc::collections::BTreeSet<$crate::DataIdentifierCow>, $crate::DataError> {
170                 match marker.id.hashed() {
171                     $(
172                         $(#[$cfg])?
173                         h if h == <$struct_m as $crate::DataMarker>::INFO.id.hashed() => {
174                             $crate::IterableDataProvider::<$struct_m>::iter_ids(self)
175                         }
176                     )+,
177                     _ => Err($crate::DataErrorKind::MarkerNotFound.with_marker(marker))
178                 }
179             }
180         }
181     }
182 }
183 #[doc(inline)]
184 pub use __impl_iterable_dynamic_data_provider as impl_iterable_dynamic_data_provider;
185