Hash a join key from raw msgpack bytes — zero String allocation. For single-field keys: hashes the raw value bytes directly. For composite keys: hashes each field's raw bytes sequentially. Returns `(hash, key_ranges)` — the ranges are kept for collision resolution via memcmp.
(
doc: &[u8],
keys: &[&str],
state: &std::collections::hash_map::RandomState,
)
| 12 | /// For composite keys: hashes each field's raw bytes sequentially. |
| 13 | /// Returns `(hash, key_ranges)` — the ranges are kept for collision resolution via memcmp. |
| 14 | pub(super) fn hash_join_key( |
| 15 | doc: &[u8], |
| 16 | keys: &[&str], |
| 17 | state: &std::collections::hash_map::RandomState, |
| 18 | ) -> (u64, Vec<(usize, usize)>) { |
| 19 | use std::hash::{BuildHasher, Hasher}; |
| 20 | let mut hasher = state.build_hasher(); |
| 21 | let mut ranges = Vec::with_capacity(keys.len()); |
| 22 | for key in keys { |
| 23 | if let Some((start, end)) = extract_join_key_range(doc, key) { |
| 24 | hasher.write(&doc[start..end]); |
| 25 | ranges.push((start, end)); |
| 26 | } else { |
| 27 | // Missing field — hash a sentinel. |
| 28 | hasher.write_u8(0xc0); // NIL tag |
| 29 | ranges.push((0, 0)); |
| 30 | } |
| 31 | } |
| 32 | (hasher.finish(), ranges) |
| 33 | } |
| 34 | |
| 35 | fn extract_join_key_range(doc: &[u8], key: &str) -> Option<(usize, usize)> { |
| 36 | msgpack_scan::extract_field(doc, 0, key).or_else(|| { |
no test coverage detected