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 | //! Marker types and traits for DataProvider. |
6 | |
7 | use core::marker::PhantomData; |
8 | |
9 | use crate::{data_key, DataKey, DataProvider, DataProviderWithKey}; |
10 | use yoke::Yokeable; |
11 | |
12 | /// Trait marker for data structs. All types delivered by the data provider must be associated with |
13 | /// something implementing this trait. |
14 | /// |
15 | /// Structs implementing this trait are normally generated with the [`data_struct`] macro. |
16 | /// |
17 | /// By convention, the non-standard `Marker` suffix is used by types implementing DataMarker. |
18 | /// |
19 | /// In addition to a marker type implementing DataMarker, the following impls must also be present |
20 | /// for the data struct: |
21 | /// |
22 | /// - `impl<'a> Yokeable<'a>` (required) |
23 | /// - `impl ZeroFrom<Self>` |
24 | /// |
25 | /// Also see [`KeyedDataMarker`]. |
26 | /// |
27 | /// Note: `DataMarker`s are quasi-const-generic compile-time objects, and as such are expected |
28 | /// to be unit structs. As this is not something that can be enforced by the type system, we |
29 | /// currently only have a `'static` bound on them (which is needed by a lot of our code). |
30 | /// |
31 | /// # Examples |
32 | /// |
33 | /// Manually implementing DataMarker for a custom type: |
34 | /// |
35 | /// ``` |
36 | /// use icu_provider::prelude::*; |
37 | /// use std::borrow::Cow; |
38 | /// |
39 | /// #[derive(yoke::Yokeable, zerofrom::ZeroFrom)] |
40 | /// struct MyDataStruct<'data> { |
41 | /// message: Cow<'data, str>, |
42 | /// } |
43 | /// |
44 | /// struct MyDataStructMarker; |
45 | /// |
46 | /// impl DataMarker for MyDataStructMarker { |
47 | /// type Yokeable = MyDataStruct<'static>; |
48 | /// } |
49 | /// |
50 | /// // We can now use MyDataStruct with DataProvider: |
51 | /// let s = MyDataStruct { |
52 | /// message: Cow::Owned("Hello World" .into()), |
53 | /// }; |
54 | /// let payload = DataPayload::<MyDataStructMarker>::from_owned(s); |
55 | /// assert_eq!(payload.get().message, "Hello World" ); |
56 | /// ``` |
57 | /// |
58 | /// [`data_struct`]: crate::data_struct |
59 | pub trait DataMarker: 'static { |
60 | /// A type that implements [`Yokeable`]. This should typically be the `'static` version of a |
61 | /// data struct. |
62 | type Yokeable: for<'a> dynYokeable<'a>; |
63 | } |
64 | |
65 | /// A [`DataMarker`] with a [`DataKey`] attached. |
66 | /// |
67 | /// Structs implementing this trait are normally generated with the [`data_struct!`] macro. |
68 | /// |
69 | /// Implementing this trait enables this marker to be used with the main [`DataProvider`] trait. |
70 | /// Most markers should be associated with a specific key and should therefore implement this |
71 | /// trait. |
72 | /// |
73 | /// [`BufferMarker`] and [`AnyMarker`] are examples of markers that do _not_ implement this trait |
74 | /// because they are not specific to a single key. |
75 | /// |
76 | /// Note: `KeyedDataMarker`s are quasi-const-generic compile-time objects, and as such are expected |
77 | /// to be unit structs. As this is not something that can be enforced by the type system, we |
78 | /// currently only have a `'static` bound on them (which is needed by a lot of our code). |
79 | /// |
80 | /// [`data_struct!`]: crate::data_struct |
81 | /// [`DataProvider`]: crate::DataProvider |
82 | /// [`BufferMarker`]: crate::BufferMarker |
83 | /// [`AnyMarker`]: crate::AnyMarker |
84 | pub trait KeyedDataMarker: DataMarker { |
85 | /// The single [`DataKey`] associated with this marker. |
86 | const KEY: DataKey; |
87 | |
88 | /// Binds this [`KeyedDataMarker`] to a provider supporting it. |
89 | fn bind<P>(provider: P) -> DataProviderWithKey<Self, P> |
90 | where |
91 | P: DataProvider<Self>, |
92 | Self: Sized, |
93 | { |
94 | DataProviderWithKey::new(inner:provider) |
95 | } |
96 | } |
97 | |
98 | /// A [`DataMarker`] that never returns data. |
99 | /// |
100 | /// All types that have non-blanket impls of `DataProvider<M>` are expected to explicitly |
101 | /// implement `DataProvider<NeverMarker<Y>>`, returning [`DataErrorKind::MissingDataKey`]. |
102 | /// See [`impl_data_provider_never_marker!`]. |
103 | /// |
104 | /// [`DataErrorKind::MissingDataKey`]: crate::DataErrorKind::MissingDataKey |
105 | /// [`impl_data_provider_never_marker!`]: crate::impl_data_provider_never_marker |
106 | /// |
107 | /// # Examples |
108 | /// |
109 | /// ``` |
110 | /// use icu_locid::langid; |
111 | /// use icu_provider::hello_world::*; |
112 | /// use icu_provider::prelude::*; |
113 | /// use icu_provider::NeverMarker; |
114 | /// |
115 | /// let buffer_provider = HelloWorldProvider.into_json_provider(); |
116 | /// |
117 | /// let result = DataProvider::<NeverMarker<HelloWorldV1<'static>>>::load( |
118 | /// &buffer_provider.as_deserializing(), |
119 | /// DataRequest { |
120 | /// locale: &langid!("en" ).into(), |
121 | /// metadata: Default::default(), |
122 | /// }, |
123 | /// ); |
124 | /// |
125 | /// assert!(matches!( |
126 | /// result, |
127 | /// Err(DataError { |
128 | /// kind: DataErrorKind::MissingDataKey, |
129 | /// .. |
130 | /// }) |
131 | /// )); |
132 | /// ``` |
133 | #[derive (Debug, Copy, Clone)] |
134 | pub struct NeverMarker<Y>(PhantomData<Y>); |
135 | |
136 | impl<Y> DataMarker for NeverMarker<Y> |
137 | where |
138 | for<'a> Y: Yokeable<'a>, |
139 | { |
140 | type Yokeable = Y; |
141 | } |
142 | |
143 | impl<Y> KeyedDataMarker for NeverMarker<Y> |
144 | where |
145 | for<'a> Y: Yokeable<'a>, |
146 | { |
147 | const KEY: DataKey = data_key!("_never@1" ); |
148 | } |
149 | |
150 | /// Implements `DataProvider<NeverMarker<Y>>` on a struct. |
151 | /// |
152 | /// For more information, see [`NeverMarker`]. |
153 | /// |
154 | /// # Examples |
155 | /// |
156 | /// ``` |
157 | /// use icu_locid::langid; |
158 | /// use icu_provider::hello_world::*; |
159 | /// use icu_provider::prelude::*; |
160 | /// use icu_provider::NeverMarker; |
161 | /// |
162 | /// struct MyProvider; |
163 | /// |
164 | /// icu_provider::impl_data_provider_never_marker!(MyProvider); |
165 | /// |
166 | /// let result = DataProvider::<NeverMarker<HelloWorldV1<'static>>>::load( |
167 | /// &MyProvider, |
168 | /// DataRequest { |
169 | /// locale: &langid!("und" ).into(), |
170 | /// metadata: Default::default(), |
171 | /// }, |
172 | /// ); |
173 | /// |
174 | /// assert!(matches!( |
175 | /// result, |
176 | /// Err(DataError { |
177 | /// kind: DataErrorKind::MissingDataKey, |
178 | /// .. |
179 | /// }) |
180 | /// )); |
181 | /// ``` |
182 | #[macro_export ] |
183 | macro_rules! impl_data_provider_never_marker { |
184 | ($ty:path) => { |
185 | impl<Y> $crate::DataProvider<$crate::NeverMarker<Y>> for $ty |
186 | where |
187 | for<'a> Y: $crate::yoke::Yokeable<'a>, |
188 | { |
189 | fn load( |
190 | &self, |
191 | req: $crate::DataRequest, |
192 | ) -> Result<$crate::DataResponse<$crate::NeverMarker<Y>>, $crate::DataError> { |
193 | Err($crate::DataErrorKind::MissingDataKey.with_req( |
194 | <$crate::NeverMarker<Y> as $crate::KeyedDataMarker>::KEY, |
195 | req, |
196 | )) |
197 | } |
198 | } |
199 | }; |
200 | } |
201 | |