icu_provider/
varule_traits.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
5use zerovec::ule::VarULE;
6
7#[cfg(feature = "alloc")]
8use zerovec::{maps::ZeroMapKV, ZeroMap2d};
9
10/// A trait that associates a [`VarULE`] type with a data struct.
11///
12/// Some data structs can be represented compactly as a single [`VarULE`],
13/// such as `str` or a packed pattern. This trait allows for data providers
14/// to use optimizations for such types.
15///
16/// ❗ Not all data structs benefit from this optimization. It works best when the
17/// data struct is multiplied across a large number of data marker attributes.
18///
19/// Both [`MaybeAsVarULE`] and [`MaybeEncodeAsVarULE`] should be implemented
20/// on all data structs. The [`data_struct!`](crate::data_struct) macro provides an impl.
21pub trait MaybeAsVarULE {
22    /// The [`VarULE`] type for this data struct, or `[()]`
23    /// if it cannot be represented as [`VarULE`].
24    type EncodedStruct: ?Sized + VarULE;
25}
26
27/// Export-only trait associated with [`MaybeAsVarULE`]. See that trait
28/// for additional details.
29///
30/// ✨ *Enabled with the `export` Cargo feature.*
31#[cfg(feature = "export")]
32pub trait MaybeEncodeAsVarULE: MaybeAsVarULE {
33    /// Returns the [`MaybeAsVarULE::EncodedStruct`] that represents this data struct,
34    /// or `None` if the data struct does not support this representation.
35    fn maybe_encode_as_varule(&self) -> Option<&Self::EncodedStruct>;
36}
37
38/// Implements required traits on data structs, such as [`MaybeEncodeAsVarULE`].
39#[macro_export] // canonical location is crate root
40macro_rules! data_struct {
41    (<$generic:ident: $bound:tt> $ty:path $(, $(#[$attr:meta])*)?) => {
42        impl<$generic: $bound> $crate::ule::MaybeAsVarULE for $ty {
43            type EncodedStruct = [()];
44        }
45        $($(#[$attr])*)?
46        impl<$generic: $bound> $crate::ule::MaybeEncodeAsVarULE for $ty {
47            fn maybe_encode_as_varule(&self) -> Option<&Self::EncodedStruct> {
48                None
49            }
50        }
51    };
52    ($ty:path $(, $(#[$attr:meta])*)?) => {
53        impl $crate::ule::MaybeAsVarULE for $ty {
54            type EncodedStruct = [()];
55        }
56        $($(#[$attr])*)?
57        impl $crate::ule::MaybeEncodeAsVarULE for $ty {
58            fn maybe_encode_as_varule(&self) -> Option<&Self::EncodedStruct> {
59                None
60            }
61        }
62    };
63    (
64        $ty:ty,
65        varule: $varule:ty,
66        $(#[$attr:meta])*
67        encode_as_varule: $encode_as_varule:expr
68    ) => {
69        impl<'data> $crate::ule::MaybeAsVarULE for $ty {
70            type EncodedStruct = $varule;
71        }
72        $(#[$attr])*
73        impl<'data> $crate::ule::MaybeEncodeAsVarULE for $ty {
74            fn maybe_encode_as_varule(&self) -> Option<&Self::EncodedStruct> {
75                // Workaround for <https://rust-lang.github.io/rfcs/3216-closure-lifetime-binder.html>
76                fn bind_lifetimes<F>(f: F) -> F where F: for<'data> Fn(&'data $ty) -> &'data $varule { f }
77                Some(bind_lifetimes($encode_as_varule)(self))
78            }
79        }
80    };
81}
82
83//=== Standard impls ===//
84
85#[cfg(feature = "alloc")]
86impl<'a, K0, K1, V> MaybeAsVarULE for ZeroMap2d<'a, K0, K1, V>
87where
88    K0: ZeroMapKV<'a>,
89    K1: ZeroMapKV<'a>,
90    V: ZeroMapKV<'a>,
91    K0: ?Sized,
92    K1: ?Sized,
93    V: ?Sized,
94{
95    type EncodedStruct = [()];
96}
97
98#[cfg(feature = "alloc")]
99#[cfg(feature = "export")]
100impl<'a, K0, K1, V> MaybeEncodeAsVarULE for ZeroMap2d<'a, K0, K1, V>
101where
102    K0: ZeroMapKV<'a>,
103    K1: ZeroMapKV<'a>,
104    V: ZeroMapKV<'a>,
105    K0: ?Sized,
106    K1: ?Sized,
107    V: ?Sized,
108{
109    fn maybe_encode_as_varule(&self) -> Option<&Self::EncodedStruct> {
110        None
111    }
112}
113
114impl<T, const N: usize> MaybeAsVarULE for [T; N] {
115    type EncodedStruct = [()];
116}
117
118#[cfg(feature = "export")]
119impl<T, const N: usize> MaybeEncodeAsVarULE for [T; N] {
120    fn maybe_encode_as_varule(&self) -> Option<&Self::EncodedStruct> {
121        None
122    }
123}