iddqd/tri_hash_map/trait_defs.rs
1//! Trait definitions for `TriHashMap`.
2
3use alloc::{boxed::Box, rc::Rc, sync::Arc};
4use core::hash::Hash;
5
6/// An item in a [`TriHashMap`].
7///
8/// This trait is used to define the keys.
9///
10/// # Examples
11///
12/// ```
13/// # #[cfg(feature = "default-hasher")] {
14/// use iddqd::{TriHashItem, TriHashMap, tri_upcast};
15///
16/// // Define a struct with three keys.
17/// #[derive(Debug, PartialEq, Eq, Hash)]
18/// struct Person {
19/// id: u32,
20/// name: String,
21/// email: String,
22/// }
23///
24/// // Implement TriHashItem for the struct.
25/// impl TriHashItem for Person {
26/// type K1<'a> = u32;
27/// type K2<'a> = &'a str;
28/// type K3<'a> = &'a str;
29///
30/// fn key1(&self) -> Self::K1<'_> {
31/// self.id
32/// }
33///
34/// fn key2(&self) -> Self::K2<'_> {
35/// &self.name
36/// }
37///
38/// fn key3(&self) -> Self::K3<'_> {
39/// &self.email
40/// }
41///
42/// tri_upcast!();
43/// }
44///
45/// // Create a TriHashMap and insert items.
46/// let mut map = TriHashMap::new();
47/// map.insert_unique(Person {
48/// id: 1,
49/// name: "Alice".to_string(),
50/// email: "alice@example.com".to_string(),
51/// })
52/// .unwrap();
53/// map.insert_unique(Person {
54/// id: 2,
55/// name: "Bob".to_string(),
56/// email: "bob@example.com".to_string(),
57/// })
58/// .unwrap();
59/// # }
60/// ```
61///
62/// [`TriHashMap`]: crate::TriHashMap
63pub trait TriHashItem {
64 /// The first key type.
65 type K1<'a>: Eq + Hash
66 where
67 Self: 'a;
68
69 /// The second key type.
70 type K2<'a>: Eq + Hash
71 where
72 Self: 'a;
73
74 /// The third key type.
75 type K3<'a>: Eq + Hash
76 where
77 Self: 'a;
78
79 /// Retrieves the first key.
80 fn key1(&self) -> Self::K1<'_>;
81
82 /// Retrieves the second key.
83 fn key2(&self) -> Self::K2<'_>;
84
85 /// Retrieves the third key.
86 fn key3(&self) -> Self::K3<'_>;
87
88 /// Upcasts the first key to a shorter lifetime, in effect asserting that
89 /// the lifetime `'a` on [`TriHashItem::K1`] is covariant.
90 ///
91 /// Typically implemented via the [`tri_upcast`] macro.
92 ///
93 /// [`tri_upcast`]: crate::tri_upcast
94 fn upcast_key1<'short, 'long: 'short>(
95 long: Self::K1<'long>,
96 ) -> Self::K1<'short>;
97
98 /// Upcasts the second key to a shorter lifetime, in effect asserting that
99 /// the lifetime `'a` on [`TriHashItem::K2`] is covariant.
100 ///
101 /// Typically implemented via the [`tri_upcast`] macro.
102 ///
103 /// [`tri_upcast`]: crate::tri_upcast
104 fn upcast_key2<'short, 'long: 'short>(
105 long: Self::K2<'long>,
106 ) -> Self::K2<'short>;
107
108 /// Upcasts the third key to a shorter lifetime, in effect asserting that
109 /// the lifetime `'a` on [`TriHashItem::K3`] is covariant.
110 ///
111 /// Typically implemented via the [`tri_upcast`] macro.
112 ///
113 /// [`tri_upcast`]: crate::tri_upcast
114 fn upcast_key3<'short, 'long: 'short>(
115 long: Self::K3<'long>,
116 ) -> Self::K3<'short>;
117}
118
119macro_rules! impl_for_ref {
120 ($type:ty) => {
121 impl<'b, T: 'b + ?Sized + TriHashItem> TriHashItem for $type {
122 type K1<'a>
123 = T::K1<'a>
124 where
125 Self: 'a;
126 type K2<'a>
127 = T::K2<'a>
128 where
129 Self: 'a;
130 type K3<'a>
131 = T::K3<'a>
132 where
133 Self: 'a;
134
135 fn key1(&self) -> Self::K1<'_> {
136 (**self).key1()
137 }
138
139 fn key2(&self) -> Self::K2<'_> {
140 (**self).key2()
141 }
142
143 fn key3(&self) -> Self::K3<'_> {
144 (**self).key3()
145 }
146
147 fn upcast_key1<'short, 'long: 'short>(
148 long: Self::K1<'long>,
149 ) -> Self::K1<'short>
150 where
151 Self: 'long,
152 {
153 T::upcast_key1(long)
154 }
155
156 fn upcast_key2<'short, 'long: 'short>(
157 long: Self::K2<'long>,
158 ) -> Self::K2<'short>
159 where
160 Self: 'long,
161 {
162 T::upcast_key2(long)
163 }
164
165 fn upcast_key3<'short, 'long: 'short>(
166 long: Self::K3<'long>,
167 ) -> Self::K3<'short>
168 where
169 Self: 'long,
170 {
171 T::upcast_key3(long)
172 }
173 }
174 };
175}
176
177impl_for_ref!(&'b T);
178impl_for_ref!(&'b mut T);
179
180macro_rules! impl_for_box {
181 ($type:ty) => {
182 impl<T: ?Sized + TriHashItem> TriHashItem for $type {
183 type K1<'a>
184 = T::K1<'a>
185 where
186 Self: 'a;
187
188 type K2<'a>
189 = T::K2<'a>
190 where
191 Self: 'a;
192
193 type K3<'a>
194 = T::K3<'a>
195 where
196 Self: 'a;
197
198 fn key1(&self) -> Self::K1<'_> {
199 (**self).key1()
200 }
201
202 fn key2(&self) -> Self::K2<'_> {
203 (**self).key2()
204 }
205
206 fn key3(&self) -> Self::K3<'_> {
207 (**self).key3()
208 }
209
210 fn upcast_key1<'short, 'long: 'short>(
211 long: Self::K1<'long>,
212 ) -> Self::K1<'short> {
213 T::upcast_key1(long)
214 }
215
216 fn upcast_key2<'short, 'long: 'short>(
217 long: Self::K2<'long>,
218 ) -> Self::K2<'short> {
219 T::upcast_key2(long)
220 }
221
222 fn upcast_key3<'short, 'long: 'short>(
223 long: Self::K3<'long>,
224 ) -> Self::K3<'short> {
225 T::upcast_key3(long)
226 }
227 }
228 };
229}
230
231impl_for_box!(Box<T>);
232impl_for_box!(Rc<T>);
233impl_for_box!(Arc<T>);