icu_provider/
marker.rs

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
7use core::marker::PhantomData;
8
9use crate::{data_key, DataKey, DataProvider, DataProviderWithKey};
10use 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
59pub 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> Yokeable<'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
84pub 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(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)]
134pub struct NeverMarker<Y>(PhantomData<Y>);
135
136impl<Y> DataMarker for NeverMarker<Y>
137where
138    for<'a> Y: Yokeable<'a>,
139{
140    type Yokeable = Y;
141}
142
143impl<Y> KeyedDataMarker for NeverMarker<Y>
144where
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]
183macro_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}