Skip to main content

noxu_tree/
key.rs

1//! Key comparison and prefix utilities.
2//!
3//!
4//! Provides utilities for comparing keys and computing key prefixes for
5//! key compression in the B-tree.
6
7use std::cmp::Ordering;
8
9/// Empty key constant.
10pub const EMPTY_KEY: &[u8] = &[];
11
12/// Trait for custom key comparison.
13///
14/// Allows databases to use application-specific ordering rather than
15/// the default unsigned byte-by-byte comparison.
16pub trait KeyComparator: Send + Sync {
17    /// Compares two keys and returns their ordering.
18    ///
19    /// # Arguments
20    /// * `key1` - First key to compare
21    /// * `key2` - Second key to compare
22    ///
23    /// # Returns
24    /// `Ordering::Less` if key1 < key2, `Ordering::Equal` if equal,
25    /// `Ordering::Greater` if key1 > key2
26    fn compare(&self, key1: &[u8], key2: &[u8]) -> Ordering;
27}
28
29/// Compares two keys using unsigned byte-by-byte comparison.
30///
31/// This is the default comparison used when no custom comparator is specified.
32/// Each byte is treated as an unsigned value (0-255).
33///
34/// # Arguments
35/// * `key1` - First key
36/// * `key2` - Second key
37///
38/// # Returns
39/// `Ordering::Less` if key1 < key2, `Ordering::Equal` if equal,
40/// `Ordering::Greater` if key1 > key2
41pub fn compare_unsigned_bytes(key1: &[u8], key2: &[u8]) -> Ordering {
42    // Rust's slice comparison already does unsigned byte-by-byte comparison
43    key1.cmp(key2)
44}
45
46/// Compares two keys using either a custom comparator or default unsigned comparison.
47///
48/// # Arguments
49/// * `key1` - First key
50/// * `key2` - Second key
51/// * `comparator` - Optional custom comparator. If None, uses unsigned byte comparison.
52///
53/// # Returns
54/// `Ordering::Less` if key1 < key2, `Ordering::Equal` if equal,
55/// `Ordering::Greater` if key1 > key2
56pub fn compare_keys(
57    key1: &[u8],
58    key2: &[u8],
59    comparator: Option<&dyn KeyComparator>,
60) -> Ordering {
61    match comparator {
62        Some(cmp) => cmp.compare(key1, key2),
63        None => compare_unsigned_bytes(key1, key2),
64    }
65}
66
67/// Returns the length of the common prefix between two keys.
68///
69/// Used for key prefix compression in the B-tree. The returned length
70/// is the number of leading bytes that are identical in both keys.
71///
72/// # Arguments
73/// * `key1` - First key
74/// * `key2` - Second key
75///
76/// # Returns
77/// The number of bytes in the common prefix (0 if no common prefix)
78pub fn get_key_prefix_length(key1: &[u8], key2: &[u8]) -> usize {
79    let min_len = key1.len().min(key2.len());
80    let mut prefix_len = 0;
81
82    for i in 0..min_len {
83        if key1[i] == key2[i] {
84            prefix_len += 1;
85        } else {
86            break;
87        }
88    }
89
90    prefix_len
91}
92
93/// Creates a key prefix from the common leading bytes of two keys.
94///
95/// Returns `None` if the keys have no common prefix (differ at first byte).
96/// Returns `Some(prefix)` if there is at least one common leading byte.
97///
98/// # Arguments
99/// * `key1` - First key
100/// * `key2` - Second key
101///
102/// # Returns
103/// `Some(Vec<u8>)` containing the common prefix, or `None` if no common prefix
104pub fn create_key_prefix(key1: &[u8], key2: &[u8]) -> Option<Vec<u8>> {
105    let prefix_len = get_key_prefix_length(key1, key2);
106
107    if prefix_len == 0 { None } else { Some(key1[..prefix_len].to_vec()) }
108}
109
110/// Default key comparator that uses unsigned byte comparison.
111#[derive(Debug, Clone, Copy)]
112pub struct DefaultComparator;
113
114impl KeyComparator for DefaultComparator {
115    fn compare(&self, key1: &[u8], key2: &[u8]) -> Ordering {
116        compare_unsigned_bytes(key1, key2)
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_compare_unsigned_bytes() {
126        let k1 = b"abc";
127        let k2 = b"abd";
128        let k3 = b"abc";
129
130        assert_eq!(compare_unsigned_bytes(k1, k2), Ordering::Less);
131        assert_eq!(compare_unsigned_bytes(k2, k1), Ordering::Greater);
132        assert_eq!(compare_unsigned_bytes(k1, k3), Ordering::Equal);
133    }
134
135    #[test]
136    fn test_compare_different_lengths() {
137        let k1 = b"abc";
138        let k2 = b"abcd";
139
140        assert_eq!(compare_unsigned_bytes(k1, k2), Ordering::Less);
141        assert_eq!(compare_unsigned_bytes(k2, k1), Ordering::Greater);
142    }
143
144    #[test]
145    fn test_compare_empty_keys() {
146        let k1 = EMPTY_KEY;
147        let k2 = b"x";
148
149        assert_eq!(compare_unsigned_bytes(k1, k2), Ordering::Less);
150        assert_eq!(compare_unsigned_bytes(k1, k1), Ordering::Equal);
151    }
152
153    #[test]
154    fn test_compare_with_unsigned_bytes() {
155        // Test that bytes are treated as unsigned (0-255)
156        let k1 = &[0xFE_u8];
157        let k2 = &[0x01_u8];
158
159        // 0xFE (254) > 0x01 (1) when treated as unsigned
160        assert_eq!(compare_unsigned_bytes(k1, k2), Ordering::Greater);
161    }
162
163    #[test]
164    fn test_get_key_prefix_length() {
165        let k1 = b"abcdef";
166        let k2 = b"abcxyz";
167
168        assert_eq!(get_key_prefix_length(k1, k2), 3); // "abc"
169
170        let k3 = b"xyz";
171        assert_eq!(get_key_prefix_length(k1, k3), 0);
172
173        let k4 = b"abcdef";
174        assert_eq!(get_key_prefix_length(k1, k4), 6); // Full match
175    }
176
177    #[test]
178    fn test_get_key_prefix_length_different_lengths() {
179        let k1 = b"abc";
180        let k2 = b"abcdef";
181
182        assert_eq!(get_key_prefix_length(k1, k2), 3);
183        assert_eq!(get_key_prefix_length(k2, k1), 3);
184    }
185
186    #[test]
187    fn test_create_key_prefix() {
188        let k1 = b"abcdef";
189        let k2 = b"abcxyz";
190
191        let prefix = create_key_prefix(k1, k2);
192        assert_eq!(prefix, Some(b"abc".to_vec()));
193
194        let k3 = b"xyz";
195        let no_prefix = create_key_prefix(k1, k3);
196        assert_eq!(no_prefix, None);
197    }
198
199    #[test]
200    fn test_create_key_prefix_empty() {
201        let k1 = EMPTY_KEY;
202        let k2 = b"abc";
203
204        assert_eq!(create_key_prefix(k1, k2), None);
205        assert_eq!(create_key_prefix(k2, k1), None);
206    }
207
208    #[test]
209    fn test_compare_keys_with_default() {
210        let k1 = b"abc";
211        let k2 = b"abd";
212
213        assert_eq!(compare_keys(k1, k2, None), Ordering::Less);
214    }
215
216    #[test]
217    fn test_compare_keys_with_custom_comparator() {
218        struct ReverseComparator;
219
220        impl KeyComparator for ReverseComparator {
221            fn compare(&self, key1: &[u8], key2: &[u8]) -> Ordering {
222                key2.cmp(key1) // Reverse order
223            }
224        }
225
226        let k1 = b"abc";
227        let k2 = b"abd";
228        let cmp = ReverseComparator;
229
230        // With reverse comparator, "abc" > "abd"
231        assert_eq!(compare_keys(k1, k2, Some(&cmp)), Ordering::Greater);
232    }
233
234    #[test]
235    fn test_default_comparator() {
236        let cmp = DefaultComparator;
237        let k1 = b"abc";
238        let k2 = b"abd";
239
240        assert_eq!(cmp.compare(k1, k2), Ordering::Less);
241        assert_eq!(compare_keys(k1, k2, Some(&cmp)), Ordering::Less);
242    }
243}