Skip to main content

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
5#[cfg(feature = "export")]
6use zerovec::ule::EncodeAsVarULE;
7use zerovec::ule::VarULE;
8
9#[cfg(feature = "alloc")]
10use zerovec::{maps::ZeroMapKV, ZeroMap, ZeroMap2d};
11
12/// A trait that associates a [`VarULE`] type with a data struct.
13///
14/// Some data structs can be represented compactly as a single [`VarULE`],
15/// such as `str` or a packed pattern. This trait allows for data providers
16/// to use optimizations for such types.
17///
18/// ❗ Not all data structs benefit from this optimization. It works best when the
19/// data struct is multiplied across a large number of data marker attributes.
20///
21/// Both [`MaybeAsVarULE`] and [`MaybeEncodeAsVarULE`] should be implemented
22/// on all data structs. The [`data_struct!`](crate::data_struct) macro provides an impl.
23pub trait MaybeAsVarULE {
24    /// The [`VarULE`] type for this data struct, or `[()]`
25    /// if it cannot be represented as [`VarULE`].
26    type EncodedStruct: ?Sized + VarULE;
27}
28
29/// Export-only trait associated with [`MaybeAsVarULE`]. See that trait
30/// for additional details.
31///
32/// ✨ *Enabled with the `export` Cargo feature.*
33#[cfg(feature = "export")]
34pub trait MaybeEncodeAsVarULE: MaybeAsVarULE {
35    /// The type returned by [`Self::maybe_as_encodeable`].
36    type EncodeableStruct<'a>: EncodeAsVarULE<Self::EncodedStruct>
37    where
38        Self: 'a;
39    /// Returns something encodeable to the [`MaybeAsVarULE::EncodedStruct`] that represents
40    /// this data struct, or `None` if the data struct does not support this representation.
41    fn maybe_as_encodeable<'a>(&'a self) -> Option<Self::EncodeableStruct<'a>>;
42}
43
44/// Implements required traits on data structs, such as [`MaybeEncodeAsVarULE`].
45#[macro_export] // canonical location is crate root
46macro_rules! data_struct {
47    (<$generic:ident: $bound:tt> $ty:path $(, $(#[$attr:meta])*)?) => {
48        impl<$generic: $bound> $crate::ule::MaybeAsVarULE for $ty {
49            type EncodedStruct = [()];
50        }
51        $($(#[$attr])*)?
52        impl<$generic: $bound> $crate::ule::MaybeEncodeAsVarULE for $ty {
53            type EncodeableStruct<'b> = &'b [()] where Self: 'b;
54            fn maybe_as_encodeable<'b>(&'b self) -> Option<Self::EncodeableStruct<'b>> {
55                None
56            }
57        }
58    };
59    ($ty:path $(, $(#[$attr:meta])*)?) => {
60        impl $crate::ule::MaybeAsVarULE for $ty {
61            type EncodedStruct = [()];
62        }
63        $($(#[$attr])*)?
64        impl $crate::ule::MaybeEncodeAsVarULE for $ty {
65            type EncodeableStruct<'b> = &'b [()] where Self: 'b;
66            fn maybe_as_encodeable<'b>(&'b self) -> Option<Self::EncodeableStruct<'b>> {
67                None
68            }
69        }
70    };
71    (
72        $ty:ty,
73        varule: $varule:ty,
74        $(#[$attr:meta])*
75        encode_as_varule: $encode_as_varule:expr
76    ) => {
77        impl<'data> $crate::ule::MaybeAsVarULE for $ty {
78            type EncodedStruct = $varule;
79        }
80        $(#[$attr])*
81        impl<'data> $crate::ule::MaybeEncodeAsVarULE for $ty {
82            type EncodeableStruct<'b> = &'b $varule where Self: 'b;
83            fn maybe_as_encodeable<'b>(&'b self) -> Option<Self::EncodeableStruct<'b>> {
84                // Workaround for <https://rust-lang.github.io/rfcs/3216-closure-lifetime-binder.html>
85                fn bind_lifetimes<F>(f: F) -> F where F: for<'data> Fn(&'data $ty) -> &'data $varule { f }
86                Some(bind_lifetimes($encode_as_varule)(self))
87            }
88        }
89    };
90}
91
92//=== Standard impls ===//
93
94#[cfg(feature = "alloc")]
95impl<'a, K0, V> MaybeAsVarULE for ZeroMap<'a, K0, V>
96where
97    K0: ZeroMapKV<'a>,
98    V: ZeroMapKV<'a>,
99    K0: ?Sized,
100    V: ?Sized,
101{
102    type EncodedStruct = [()];
103}
104
105#[cfg(feature = "alloc")]
106#[cfg(feature = "export")]
107impl<'a, K0, V> MaybeEncodeAsVarULE for ZeroMap<'a, K0, V>
108where
109    K0: ZeroMapKV<'a>,
110    V: ZeroMapKV<'a>,
111    K0: ?Sized,
112    V: ?Sized,
113{
114    type EncodeableStruct<'b>
115        = &'b [()]
116    where
117        Self: 'b;
118    fn maybe_as_encodeable<'b>(&'b self) -> Option<Self::EncodeableStruct<'b>> {
119        None
120    }
121}
122
123#[cfg(feature = "alloc")]
124impl<'a, K0, K1, V> MaybeAsVarULE for ZeroMap2d<'a, K0, K1, V>
125where
126    K0: ZeroMapKV<'a>,
127    K1: ZeroMapKV<'a>,
128    V: ZeroMapKV<'a>,
129    K0: ?Sized,
130    K1: ?Sized,
131    V: ?Sized,
132{
133    type EncodedStruct = [()];
134}
135
136#[cfg(feature = "alloc")]
137#[cfg(feature = "export")]
138impl<'a, K0, K1, V> MaybeEncodeAsVarULE for ZeroMap2d<'a, K0, K1, V>
139where
140    K0: ZeroMapKV<'a>,
141    K1: ZeroMapKV<'a>,
142    V: ZeroMapKV<'a>,
143    K0: ?Sized,
144    K1: ?Sized,
145    V: ?Sized,
146{
147    type EncodeableStruct<'b>
148        = &'b [()]
149    where
150        Self: 'b;
151    fn maybe_as_encodeable<'b>(&'b self) -> Option<Self::EncodeableStruct<'b>> {
152        None
153    }
154}
155
156impl<T, const N: usize> MaybeAsVarULE for [T; N] {
157    type EncodedStruct = [()];
158}
159
160#[cfg(feature = "export")]
161impl<T, const N: usize> MaybeEncodeAsVarULE for [T; N] {
162    type EncodeableStruct<'a>
163        = &'a [()]
164    where
165        Self: 'a;
166    fn maybe_as_encodeable<'a>(&'a self) -> Option<Self::EncodeableStruct<'a>> {
167        None
168    }
169}
170
171impl MaybeAsVarULE for u16 {
172    type EncodedStruct = [()];
173}
174
175#[cfg(feature = "export")]
176impl MaybeEncodeAsVarULE for u16 {
177    type EncodeableStruct<'a>
178        = &'a [()]
179    where
180        Self: 'a;
181    fn maybe_as_encodeable<'a>(&'a self) -> Option<Self::EncodeableStruct<'a>> {
182        None
183    }
184}
185
186impl<'a, V: VarULE + ?Sized> MaybeAsVarULE for zerovec::VarZeroCow<'a, V> {
187    type EncodedStruct = V;
188}
189
190#[cfg(feature = "export")]
191impl<'a, V: VarULE + ?Sized> MaybeEncodeAsVarULE for zerovec::VarZeroCow<'a, V> {
192    type EncodeableStruct<'b>
193        = &'b V
194    where
195        Self: 'b;
196    fn maybe_as_encodeable<'b>(&'b self) -> Option<Self::EncodeableStruct<'b>> {
197        Some(&**self)
198    }
199}