turbo_persistence/
key.rs

1use std::{cmp::min, hash::Hasher};
2
3/// A trait for keys that can be used for hashing.
4pub trait KeyBase {
5    /// Returns the length of the key in bytes.
6    fn len(&self) -> usize;
7    fn is_empty(&self) -> bool {
8        self.len() == 0
9    }
10    /// Hashes the key. It should not include the structure of the key, only the data. E.g. `([1,
11    /// 2], [3, 4])` should hash the same as `[1, 2, 3, 4]`.
12    fn hash<H: Hasher>(&self, state: &mut H);
13}
14
15impl KeyBase for &'_ [u8] {
16    fn len(&self) -> usize {
17        <[u8]>::len(self)
18    }
19
20    fn is_empty(&self) -> bool {
21        <[u8]>::is_empty(self)
22    }
23
24    fn hash<H: Hasher>(&self, state: &mut H) {
25        for item in *self {
26            state.write_u8(*item);
27        }
28    }
29}
30
31impl<const N: usize> KeyBase for [u8; N] {
32    fn len(&self) -> usize {
33        N
34    }
35
36    fn is_empty(&self) -> bool {
37        N > 0
38    }
39
40    fn hash<H: Hasher>(&self, state: &mut H) {
41        for item in self {
42            state.write_u8(*item);
43        }
44    }
45}
46
47impl KeyBase for Vec<u8> {
48    fn len(&self) -> usize {
49        self.len()
50    }
51
52    fn is_empty(&self) -> bool {
53        self.is_empty()
54    }
55
56    fn hash<H: Hasher>(&self, state: &mut H) {
57        for item in self {
58            state.write_u8(*item);
59        }
60    }
61}
62
63impl KeyBase for u8 {
64    fn len(&self) -> usize {
65        1
66    }
67
68    fn is_empty(&self) -> bool {
69        false
70    }
71
72    fn hash<H: Hasher>(&self, state: &mut H) {
73        state.write_u8(*self);
74    }
75}
76
77impl<A: KeyBase, B: KeyBase> KeyBase for (A, B) {
78    fn len(&self) -> usize {
79        let (a, b) = self;
80        a.len() + b.len()
81    }
82
83    fn is_empty(&self) -> bool {
84        let (a, b) = self;
85        a.is_empty() && b.is_empty()
86    }
87
88    fn hash<H: Hasher>(&self, state: &mut H) {
89        let (a, b) = self;
90        KeyBase::hash(a, state);
91        KeyBase::hash(b, state);
92    }
93}
94
95impl<T: KeyBase> KeyBase for &'_ T {
96    fn len(&self) -> usize {
97        (*self).len()
98    }
99
100    fn is_empty(&self) -> bool {
101        (*self).is_empty()
102    }
103
104    fn hash<H: Hasher>(&self, state: &mut H) {
105        (*self).hash(state)
106    }
107}
108
109/// A trait for keys that can be used to query the database. They need to allow hashing and
110/// comparison with a byte slice (total order).
111pub trait QueryKey: KeyBase {
112    fn cmp(&self, key: &[u8]) -> std::cmp::Ordering;
113}
114
115impl QueryKey for &'_ [u8] {
116    fn cmp(&self, key: &[u8]) -> std::cmp::Ordering {
117        Ord::cmp(self, &key)
118    }
119}
120
121impl<const N: usize> QueryKey for [u8; N] {
122    fn cmp(&self, key: &[u8]) -> std::cmp::Ordering {
123        Ord::cmp(&self[..], key)
124    }
125}
126
127impl QueryKey for Vec<u8> {
128    fn cmp(&self, key: &[u8]) -> std::cmp::Ordering {
129        Ord::cmp(&**self, key)
130    }
131}
132
133impl QueryKey for u8 {
134    fn cmp(&self, key: &[u8]) -> std::cmp::Ordering {
135        Ord::cmp(&[*self][..], key)
136    }
137}
138
139impl<A: QueryKey, B: QueryKey> QueryKey for (A, B) {
140    fn cmp(&self, mut key: &[u8]) -> std::cmp::Ordering {
141        let (a, b) = self;
142        let len = a.len();
143        let key_len = key.len();
144        let key_part = &key[..min(key_len, len)];
145        match a.cmp(key_part) {
146            std::cmp::Ordering::Equal => {
147                key = &key[len..];
148                b.cmp(key)
149            }
150            ord => ord,
151        }
152    }
153}
154
155impl<T: QueryKey> QueryKey for &'_ T {
156    fn cmp(&self, key: &[u8]) -> std::cmp::Ordering {
157        (*self).cmp(key)
158    }
159}
160
161/// A trait for keys that can be stored in the database. They need to allow hashing and comparison.
162pub trait StoreKey: KeyBase + Ord {
163    fn write_to(&self, buf: &mut Vec<u8>);
164}
165
166impl<const N: usize> StoreKey for [u8; N] {
167    fn write_to(&self, buf: &mut Vec<u8>) {
168        buf.extend_from_slice(&self[..]);
169    }
170}
171
172impl StoreKey for Vec<u8> {
173    fn write_to(&self, buf: &mut Vec<u8>) {
174        buf.extend_from_slice(self);
175    }
176}
177
178impl StoreKey for &'_ [u8] {
179    fn write_to(&self, buf: &mut Vec<u8>) {
180        buf.extend_from_slice(self);
181    }
182}
183
184impl StoreKey for u8 {
185    fn write_to(&self, buf: &mut Vec<u8>) {
186        buf.push(*self);
187    }
188}
189
190impl<A: StoreKey, B: StoreKey> StoreKey for (A, B) {
191    fn write_to(&self, buf: &mut Vec<u8>) {
192        self.0.write_to(buf);
193        self.1.write_to(buf);
194    }
195}
196
197impl<T: StoreKey> StoreKey for &'_ T {
198    fn write_to(&self, buf: &mut Vec<u8>) {
199        (*self).write_to(buf);
200    }
201}
202
203/// Hashes a key with a fast, deterministic hash function.
204pub fn hash_key(key: &impl KeyBase) -> u64 {
205    let mut hasher = twox_hash::XxHash64::with_seed(0);
206    key.hash(&mut hasher);
207    hasher.finish()
208}
209
210#[cfg(test)]
211mod tests {
212    use std::cmp::Ordering;
213
214    use crate::{QueryKey, key::hash_key};
215
216    #[test]
217    fn tuple() {
218        let key = (&[1, 2], &[3, 4]);
219        assert_eq!(QueryKey::cmp(&key, &[1, 2, 3, 4]), Ordering::Equal);
220        assert_eq!(QueryKey::cmp(&key, &[1, 2, 3, 3]), Ordering::Greater);
221        assert_eq!(QueryKey::cmp(&key, &[1, 2, 3, 5]), Ordering::Less);
222        assert_eq!(QueryKey::cmp(&key, &[0, 2, 3, 4]), Ordering::Greater);
223        assert_eq!(QueryKey::cmp(&key, &[2, 2, 3, 4]), Ordering::Less);
224        assert_eq!(QueryKey::cmp(&key, &[1, 2, 3, 4, 5]), Ordering::Less);
225        assert_eq!(QueryKey::cmp(&key, &[1, 2, 3]), Ordering::Greater);
226        assert_eq!(QueryKey::cmp(&key, &[1, 2]), Ordering::Greater);
227        assert_eq!(QueryKey::cmp(&key, &[1]), Ordering::Greater);
228        assert_eq!(QueryKey::cmp(&key, &[]), Ordering::Greater);
229    }
230
231    #[test]
232    fn hash() {
233        let h1 = hash_key(&[1, 2, 3, 4]);
234        let h2 = hash_key(&(&[1, 2], &[3, 4]));
235        let h3 = hash_key(&(vec![1, 2, 3], 4u8));
236        assert_eq!(h2, h1);
237        assert_eq!(h3, h1);
238    }
239}