tiny_trie/key_store.rs
1//! Key storage traits and implementations for generic trie key types.
2//!
3//! [`TrieKey`] defines how a key type provides its byte representation for trie
4//! traversal, and which [`KeyStore`] implementation backs it. Two store backends
5//! are provided:
6//!
7//! - [`BufKeyStore`] — flat buffer storage for `Vec<u8>` keys (cache-friendly,
8//! single contiguous allocation for all key bytes).
9//! - [`VecKeyStore`] — `Vec<K>` storage for any `TrieKey` type (e.g. `String`).
10//!
11//! [`ByteKey`] is a simpler trait for key types that can be converted to and
12//! from `&[u8]` while preserving ordering. It is used by [`NibbleTrie`] and
13//! other radix-trie structures that manage their own key storage internally.
14//!
15//! [`NonNullKey`] is a marker trait for [`ByteKey`] types whose byte
16//! representation is guaranteed to contain no `0x00` bytes. Tries that use
17//! null-byte sentinels (e.g. [`PolyTrie`]) require `K: NonNullKey`.
18//!
19//! [`NibbleTrie`]: crate::NibbleTrie
20//! [`PolyTrie`]: crate::PolyTrie
21// ---------------------------------------------------------------------------
22// TrieKey
23// ---------------------------------------------------------------------------
24
25/// A key type that can be stored in a trie.
26///
27/// Each key type chooses its storage backend via the associated `Store` type.
28/// The `as_bytes()` method provides the byte representation used for trie
29/// traversal (bit extraction, divergence comparison).
30///
31/// The `Default` bound is required because both store backends reserve index 0
32/// as a dummy entry (so that key index 0 can serve as the "empty" sentinel in
33/// node children arrays). `K::default()` becomes the dummy entry in `VecKeyStore`.
34pub trait TrieKey: Default {
35 /// The storage backend for this key type.
36 type Store: KeyStore<Self>;
37
38 /// Return the byte representation of this key for trie traversal.
39 fn as_bytes(&self) -> &[u8];
40}
41
42// ---------------------------------------------------------------------------
43// KeyStore
44// ---------------------------------------------------------------------------
45
46/// Storage backend for trie keys.
47///
48/// Keys are stored with 1-based indices: index 0 is a dummy entry, so real keys
49/// start at index 1. This allows 0 to be used as the "empty child" sentinel in
50/// node children arrays.
51pub trait KeyStore<K>: Default {
52 /// Push a new key, returning its 1-based key index.
53 fn push(&mut self, key: K) -> u32;
54
55 /// Get the byte representation of the key at 1-based index `ki`.
56 fn key_bytes(&self, ki: u32) -> &[u8];
57
58 /// Rollback the last push (called on duplicate-key insertion).
59 fn rollback(&mut self);
60
61 /// Number of real keys (excluding the dummy at index 0).
62 fn len(&self) -> usize;
63
64 /// Consume the store and return all real keys (skipping the dummy).
65 fn into_keys(self) -> Vec<K>;
66}
67
68// ---------------------------------------------------------------------------
69// BufKeyStore — flat buffer for Vec<u8> keys
70// ---------------------------------------------------------------------------
71
72/// Flat-buffer key storage for `Vec<u8>` keys.
73///
74/// All key bytes are packed into a single contiguous `Vec<u8>`, with a separate
75/// index array recording `(offset, length)` per key. This layout is
76/// cache-friendly for sequential access during iteration and divergence scans.
77///
78/// Key byte lengths are stored as `u16`, limiting individual keys to 65535 bytes.
79pub struct BufKeyStore {
80 buf: Vec<u8>,
81 /// (offset into buf, byte length) per key. index[0] = dummy entry.
82 index: Vec<(usize, u16)>,
83}
84
85impl Default for BufKeyStore {
86 fn default() -> Self {
87 BufKeyStore {
88 buf: Vec::new(),
89 index: vec![(0, 0)], // index[0] = dummy entry
90 }
91 }
92}
93
94impl KeyStore<Vec<u8>> for BufKeyStore {
95 fn push(&mut self, key: Vec<u8>) -> u32 {
96 let ki = self.index.len() as u32;
97 let offset = self.buf.len();
98 debug_assert!(key.len() <= u16::MAX as usize, "BufKeyStore key length exceeds u16::MAX");
99 self.buf.extend_from_slice(&key);
100 self.index.push((offset, key.len() as u16));
101 ki
102 }
103
104 fn key_bytes(&self, ki: u32) -> &[u8] {
105 let (off, len) = self.index[ki as usize];
106 &self.buf[off..off + len as usize]
107 }
108
109 fn rollback(&mut self) {
110 let (off, _len) = self.index.pop().unwrap();
111 self.buf.truncate(off);
112 }
113
114 fn len(&self) -> usize {
115 self.index.len() - 1
116 }
117
118 fn into_keys(self) -> Vec<Vec<u8>> {
119 let buf = self.buf;
120 self.index
121 .into_iter()
122 .skip(1)
123 .map(|(off, len)| buf[off..off + len as usize].to_vec())
124 .collect()
125 }
126}
127
128// ---------------------------------------------------------------------------
129// VecKeyStore<K> — Vec<K> storage for any TrieKey
130// ---------------------------------------------------------------------------
131
132/// Vec-backed key storage for any `TrieKey` type.
133///
134/// Each key is stored as its own `K` object in a `Vec<K>`. This is simpler than
135/// [`BufKeyStore`] but loses the single-allocation cache locality benefit.
136/// For fixed-size key types (e.g. `[u8; 4]`, `Ipv4Addr`), keys are stored inline
137/// in the Vec and are still contiguous.
138pub struct VecKeyStore<K: TrieKey> {
139 keys: Vec<K>, // keys[0] = K::default() dummy
140}
141
142impl<K: TrieKey> Default for VecKeyStore<K> {
143 fn default() -> Self {
144 VecKeyStore {
145 keys: vec![K::default()], // keys[0] = dummy entry
146 }
147 }
148}
149
150impl<K: TrieKey> KeyStore<K> for VecKeyStore<K> {
151 fn push(&mut self, key: K) -> u32 {
152 let ki = self.keys.len() as u32;
153 self.keys.push(key);
154 ki
155 }
156
157 fn key_bytes(&self, ki: u32) -> &[u8] {
158 self.keys[ki as usize].as_bytes()
159 }
160
161 fn rollback(&mut self) {
162 self.keys.pop();
163 }
164
165 fn len(&self) -> usize {
166 self.keys.len() - 1
167 }
168
169 fn into_keys(self) -> Vec<K> {
170 self.keys.into_iter().skip(1).collect()
171 }
172}
173
174// ---------------------------------------------------------------------------
175// ByteKey — byte-representation trait for generic trie keys
176// ---------------------------------------------------------------------------
177
178/// A key type that can be converted to and from a byte slice while preserving
179/// ordering.
180///
181/// Implementations must ensure that byte-order comparison matches the key
182/// type's natural ordering: for all `a`, `b`, `a.bytes().cmp(b.bytes())`
183/// must equal `a.cmp(b)`.
184///
185/// The [`from_bytes`] reconstruction is only ever called with byte sequences
186/// originally produced by [`bytes`], so implementations may assume valid
187/// input. The same applies to [`as_borrowed`]: it is only ever called with
188/// bytes that originated from a `bytes()` call of the same key type, so e.g.
189/// the `String` impl may assume valid UTF-8 and skip validation.
190///
191/// `ByteKey` is a subtrait of [`TrieKey`]; the byte representation is also
192/// available via [`TrieKey::as_bytes`]. The `bytes` method is the
193/// `ByteKey`-specific accessor used by radix tries that manage their own key
194/// storage ([`NibbleTrie`], [`NibTrie`]); [`TrieKey::as_bytes`] is used by
195/// [`BitTrie`] and the storage backends. Distinct names avoid ambiguity when
196/// both traits are in scope.
197///
198/// [`NibbleTrie`]: crate::NibbleTrie
199/// [`NibTrie`]: crate::NibTrie
200/// [`BitTrie`]: crate::BitTrie
201/// [`from_bytes`]: ByteKey::from_bytes
202/// [`as_borrowed`]: ByteKey::as_borrowed
203/// [`bytes`]: ByteKey::bytes
204pub trait ByteKey: TrieKey {
205 /// Borrowed view of the key, constructible from `&[u8]` without allocation.
206 ///
207 /// This is the natural zero-alloc form handed back by iteration: `Vec<u8>`
208 /// → `&'a [u8]`, `String` → `&'a str`. It
209 /// satisfies [`AsRef`]`<[u8]>` so callers can recover the raw bytes when
210 /// needed. The [`Borrow`] equivalence contract (Eq/Ord/Hash matching `Self`)
211 /// is already guaranteed by this trait's byte-order invariant and is not
212 /// re-imposed as a bound here; the trie compares raw `buf` bytes directly.
213 type Borrowed<'a>: AsRef<[u8]> + 'a
214 where
215 Self: 'a;
216
217 /// Return the byte representation of this key.
218 fn bytes(&self) -> &[u8];
219
220 /// Reconstruct an *owned* key from its byte representation. Allocates.
221 ///
222 /// `from_bytes(k.bytes())` must produce a value equivalent to `k`. Use this
223 /// only when you need an owned `K` (e.g. collecting into a `Vec<K>`); for
224 /// iteration over keys already stored in the trie, prefer [`as_borrowed`].
225 ///
226 /// [`as_borrowed`]: ByteKey::as_borrowed
227 fn from_bytes(bytes: &[u8]) -> Self;
228
229 /// View `bytes` as the borrowed key form, with no allocation.
230 ///
231 /// `as_borrowed(k.bytes())` yields a value that compares equal to `k`. Only
232 /// ever called with bytes produced by a `bytes()` call of the same key
233 /// type, so impls may skip validation (e.g. the `String` impl assumes valid
234 /// UTF-8).
235 fn as_borrowed<'a>(bytes: &'a [u8]) -> Self::Borrowed<'a>;
236}
237
238impl ByteKey for Vec<u8> {
239 type Borrowed<'a> = &'a [u8] where Self: 'a;
240 fn bytes(&self) -> &[u8] {
241 self
242 }
243 fn from_bytes(bytes: &[u8]) -> Self {
244 bytes.to_vec()
245 }
246 fn as_borrowed<'a>(bytes: &'a [u8]) -> &'a [u8] {
247 bytes
248 }
249}
250
251impl ByteKey for String {
252 type Borrowed<'a> = &'a str where Self: 'a;
253 fn bytes(&self) -> &[u8] {
254 self.as_bytes()
255 }
256 fn from_bytes(bytes: &[u8]) -> Self {
257 // Safe: bytes were originally produced by String::as_bytes (valid UTF-8).
258 String::from_utf8(bytes.to_vec()).unwrap()
259 }
260 fn as_borrowed<'a>(bytes: &'a [u8]) -> &'a str {
261 // SAFETY: `as_borrowed` is only called with bytes that originated from a
262 // `String::bytes()` call (the trie stores only such bytes), so they are
263 // valid UTF-8. Skipping the validation here is the whole point — it
264 // avoids re-validating every key on every iteration.
265 unsafe { std::str::from_utf8_unchecked(bytes) }
266 }
267}
268
269// ---------------------------------------------------------------------------
270// TrieKey implementations
271// ---------------------------------------------------------------------------
272
273impl TrieKey for Vec<u8> {
274 type Store = BufKeyStore;
275 fn as_bytes(&self) -> &[u8] {
276 self
277 }
278}
279
280impl TrieKey for String {
281 type Store = VecKeyStore<String>;
282 fn as_bytes(&self) -> &[u8] {
283 self.as_bytes()
284 }
285}
286// ---------------------------------------------------------------------------
287// Tests
288// ---------------------------------------------------------------------------
289
290#[cfg(test)]
291mod tests {
292 use super::*;
293
294 #[test]
295 fn buf_store_push_and_key_bytes() {
296 let mut store = BufKeyStore::default();
297 assert_eq!(store.len(), 0);
298
299 let ki1 = store.push(b"hello".to_vec());
300 assert_eq!(ki1, 1);
301 assert_eq!(store.key_bytes(1), b"hello");
302 assert_eq!(store.len(), 1);
303
304 let ki2 = store.push(b"world".to_vec());
305 assert_eq!(ki2, 2);
306 assert_eq!(store.key_bytes(2), b"world");
307 assert_eq!(store.len(), 2);
308 }
309
310 #[test]
311 fn buf_store_rollback() {
312 let mut store = BufKeyStore::default();
313 store.push(b"hello".to_vec());
314 store.push(b"world".to_vec());
315 assert_eq!(store.len(), 2);
316
317 store.rollback();
318 assert_eq!(store.len(), 1);
319 assert_eq!(store.key_bytes(1), b"hello");
320 }
321
322 #[test]
323 fn buf_store_into_keys() {
324 let mut store = BufKeyStore::default();
325 store.push(b"abc".to_vec());
326 store.push(b"def".to_vec());
327 let keys = store.into_keys();
328 assert_eq!(keys, vec![b"abc".to_vec(), b"def".to_vec()]);
329 }
330
331 #[test]
332 fn buf_store_empty_key() {
333 let mut store = BufKeyStore::default();
334 let ki = store.push(b"".to_vec());
335 assert_eq!(ki, 1);
336 assert_eq!(store.key_bytes(1), b"");
337 }
338
339 #[test]
340 fn buf_store_dummy_entry() {
341 let store = BufKeyStore::default();
342 assert_eq!(store.key_bytes(0), b"");
343 }
344
345 #[test]
346 fn vec_store_push_and_key_bytes() {
347 let mut store = VecKeyStore::<String>::default();
348 assert_eq!(store.len(), 0);
349
350 let ki1 = store.push("hello".to_string());
351 assert_eq!(ki1, 1);
352 assert_eq!(store.key_bytes(1), b"hello");
353 assert_eq!(store.len(), 1);
354
355 let ki2 = store.push("world".to_string());
356 assert_eq!(ki2, 2);
357 assert_eq!(store.key_bytes(2), b"world");
358 }
359
360 #[test]
361 fn vec_store_rollback() {
362 let mut store = VecKeyStore::<String>::default();
363 store.push("hello".to_string());
364 store.push("world".to_string());
365 store.rollback();
366 assert_eq!(store.len(), 1);
367 assert_eq!(store.key_bytes(1), b"hello");
368 }
369
370 #[test]
371 fn vec_store_into_keys() {
372 let mut store = VecKeyStore::<String>::default();
373 store.push("abc".to_string());
374 store.push("def".to_string());
375 let keys = store.into_keys();
376 assert_eq!(keys, vec!["abc".to_string(), "def".to_string()]);
377 }
378
379 #[test]
380 fn vec_store_dummy_entry() {
381 let store = VecKeyStore::<String>::default();
382 assert_eq!(store.key_bytes(0), b"");
383 }
384}