iddqd/bi_hash_map/
trait_defs.rs

1//! Trait definitions for `BiHashMap`.
2
3use alloc::{boxed::Box, rc::Rc, sync::Arc};
4use core::hash::Hash;
5
6/// An item in a [`BiHashMap`].
7///
8/// This trait is used to define the keys.
9///
10/// # Examples
11///
12/// ```
13/// # #[cfg(feature = "default-hasher")] {
14/// use iddqd::{BiHashItem, BiHashMap, bi_upcast};
15///
16/// // Define a struct with two keys.
17/// #[derive(Debug, PartialEq, Eq, Hash)]
18/// struct MyPair {
19///     id: u32,
20///     name: String,
21/// }
22///
23/// // Implement BiHashItem for the struct.
24/// impl BiHashItem for MyPair {
25///     type K1<'a> = u32;
26///     type K2<'a> = &'a str;
27///
28///     fn key1(&self) -> Self::K1<'_> {
29///         self.id
30///     }
31///
32///     fn key2(&self) -> Self::K2<'_> {
33///         &self.name
34///     }
35///
36///     bi_upcast!();
37/// }
38///
39/// // Create a BiHashMap and insert items.
40/// let mut map = BiHashMap::new();
41/// map.insert_unique(MyPair { id: 1, name: "Alice".to_string() }).unwrap();
42/// map.insert_unique(MyPair { id: 2, name: "Bob".to_string() }).unwrap();
43/// # }
44/// ```
45///
46/// [`BiHashMap`]: crate::BiHashMap
47pub trait BiHashItem {
48    /// The first key type.
49    type K1<'a>: Eq + Hash
50    where
51        Self: 'a;
52
53    /// The second key type.
54    type K2<'a>: Eq + Hash
55    where
56        Self: 'a;
57
58    /// Retrieves the first key.
59    fn key1(&self) -> Self::K1<'_>;
60
61    /// Retrieves the second key.
62    fn key2(&self) -> Self::K2<'_>;
63
64    /// Upcasts the first key to a shorter lifetime, in effect asserting that
65    /// the lifetime `'a` on [`BiHashItem::K1`] is covariant.
66    ///
67    /// Typically implemented via the [`bi_upcast`] macro.
68    ///
69    /// [`bi_upcast`]: crate::bi_upcast
70    fn upcast_key1<'short, 'long: 'short>(
71        long: Self::K1<'long>,
72    ) -> Self::K1<'short>;
73
74    /// Upcasts the second key to a shorter lifetime, in effect asserting that
75    /// the lifetime `'a` on [`BiHashItem::K2`] is covariant.
76    ///
77    /// Typically implemented via the [`bi_upcast`] macro.
78    ///
79    /// [`bi_upcast`]: crate::bi_upcast
80    fn upcast_key2<'short, 'long: 'short>(
81        long: Self::K2<'long>,
82    ) -> Self::K2<'short>;
83}
84
85macro_rules! impl_for_ref {
86    ($type:ty) => {
87        impl<'b, T: 'b + ?Sized + BiHashItem> BiHashItem for $type {
88            type K1<'a>
89                = T::K1<'a>
90            where
91                Self: 'a;
92            type K2<'a>
93                = T::K2<'a>
94            where
95                Self: 'a;
96
97            fn key1(&self) -> Self::K1<'_> {
98                (**self).key1()
99            }
100
101            fn key2(&self) -> Self::K2<'_> {
102                (**self).key2()
103            }
104
105            fn upcast_key1<'short, 'long: 'short>(
106                long: Self::K1<'long>,
107            ) -> Self::K1<'short>
108            where
109                Self: 'long,
110            {
111                T::upcast_key1(long)
112            }
113
114            fn upcast_key2<'short, 'long: 'short>(
115                long: Self::K2<'long>,
116            ) -> Self::K2<'short>
117            where
118                Self: 'long,
119            {
120                T::upcast_key2(long)
121            }
122        }
123    };
124}
125
126impl_for_ref!(&'b T);
127impl_for_ref!(&'b mut T);
128
129macro_rules! impl_for_box {
130    ($type:ty) => {
131        impl<T: ?Sized + BiHashItem> BiHashItem for $type {
132            type K1<'a>
133                = T::K1<'a>
134            where
135                Self: 'a;
136
137            type K2<'a>
138                = T::K2<'a>
139            where
140                Self: 'a;
141
142            fn key1(&self) -> Self::K1<'_> {
143                (**self).key1()
144            }
145
146            fn key2(&self) -> Self::K2<'_> {
147                (**self).key2()
148            }
149
150            fn upcast_key1<'short, 'long: 'short>(
151                long: Self::K1<'long>,
152            ) -> Self::K1<'short> {
153                T::upcast_key1(long)
154            }
155
156            fn upcast_key2<'short, 'long: 'short>(
157                long: Self::K2<'long>,
158            ) -> Self::K2<'short> {
159                T::upcast_key2(long)
160            }
161        }
162    };
163}
164
165impl_for_box!(Box<T>);
166impl_for_box!(Rc<T>);
167impl_for_box!(Arc<T>);