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