Skip to main content

noxu_bind/serial/
tuple_serde_binding.rs

1//! Composite binding combining sort-preserving tuple-encoded keys with
2//! serde-serialized data.
3//!
4//! Keys are encoded using the `SortKey` trait, which produces a fixed-width
5//! big-endian representation for integers (with sign-bit flipping for signed
6//! types) and null-escaped, null-terminated sequences for strings and byte
7//! slices. This encoding is sort-preserving: lexicographic byte comparison of
8//! encoded keys matches the natural `Ord` ordering of the original values.
9//!
10//! Data (the non-key payload) is serialized using serde via the compact
11//! binary encoding from [`super::simple_serial`]. Data encoding does not need
12//! to be sort-preserving because the B-tree only compares keys.
13
14use std::marker::PhantomData;
15
16use serde::Serialize;
17use serde::de::DeserializeOwned;
18
19use noxu_db::DatabaseEntry;
20
21use crate::Result;
22use crate::entry_binding::{EntityBinding, EntryBinding};
23use crate::serial::serde_binding::SerdeBinding;
24use crate::tuple::sort_key::SortKey;
25use crate::tuple::{TupleInput, TupleOutput};
26
27/// Entity binding that uses sort-preserving tuple encoding for keys and serde
28/// binary encoding for data.
29///
30/// The key type `K` must implement `SortKey`, which guarantees that the
31/// byte-wise order of encoded keys matches the `Ord` order of the original
32/// values. This makes range scans, `get_next`, `get_prev`, and sorted map
33/// operations correct without requiring a custom comparator.
34///
35/// The entity type `V` is split into a key `K` and a data payload `V` via
36/// user-provided extraction functions.
37///
38/// # Examples
39///
40/// ```ignore
41/// use serde::{Serialize, Deserialize};
42/// use noxu_bind::serial::tuple_serde_binding::TupleSerdeBinding;
43/// use noxu_bind::entry_binding::EntityBinding;
44/// use noxu_db::DatabaseEntry;
45///
46/// #[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
47/// struct Employee {
48///     id: u64,
49///     name: String,
50///     department: String,
51/// }
52///
53/// let binding = TupleSerdeBinding::<u64, Employee>::new(
54///     |emp: &Employee| emp.id,
55///     |key: u64, data: Employee| data,
56/// );
57/// ```
58pub struct TupleSerdeBinding<K, V> {
59    /// Extracts the key from the entity.
60    key_extractor: Box<dyn Fn(&V) -> K + Send + Sync>,
61    /// Combines key and data into an entity.
62    entity_creator: Box<dyn Fn(K, V) -> V + Send + Sync>,
63    _phantom: PhantomData<(K, V)>,
64}
65
66impl<K, V> TupleSerdeBinding<K, V>
67where
68    K: SortKey,
69    V: Serialize + DeserializeOwned,
70{
71    /// Creates a new composite binding with the given key extractor and entity creator.
72    ///
73    /// - `key_extractor`: extracts the sort key from an entity value.
74    /// - `entity_creator`: reconstructs the entity from key and data.
75    pub fn new<FKey, FCreate>(
76        key_extractor: FKey,
77        entity_creator: FCreate,
78    ) -> Self
79    where
80        FKey: Fn(&V) -> K + Send + Sync + 'static,
81        FCreate: Fn(K, V) -> V + Send + Sync + 'static,
82    {
83        Self {
84            key_extractor: Box::new(key_extractor),
85            entity_creator: Box::new(entity_creator),
86            _phantom: PhantomData,
87        }
88    }
89}
90
91impl<K, V> std::fmt::Debug for TupleSerdeBinding<K, V> {
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        f.debug_struct("TupleSerdeBinding")
94            .field("key_type", &std::any::type_name::<K>())
95            .field("value_type", &std::any::type_name::<V>())
96            .finish()
97    }
98}
99
100impl<K, V> EntityBinding<V> for TupleSerdeBinding<K, V>
101where
102    K: SortKey,
103    V: Serialize + DeserializeOwned,
104{
105    fn entry_to_object(
106        &self,
107        key: &DatabaseEntry,
108        data: &DatabaseEntry,
109    ) -> Result<V> {
110        let mut inp = TupleInput::new(key.data());
111        let k = K::decode_sort_key(&mut inp)?;
112        let data_binding = SerdeBinding::<V>::new();
113        let v = data_binding.entry_to_object(data)?;
114        Ok((self.entity_creator)(k, v))
115    }
116
117    fn object_to_key(&self, object: &V, key: &mut DatabaseEntry) -> Result<()> {
118        let mut out = TupleOutput::new();
119        let k = (self.key_extractor)(object);
120        k.encode_sort_key(&mut out);
121        key.set_data_vec(out.into_vec());
122        Ok(())
123    }
124
125    fn object_to_data(
126        &self,
127        object: &V,
128        data: &mut DatabaseEntry,
129    ) -> Result<()> {
130        let data_binding = SerdeBinding::<V>::new();
131        data_binding.object_to_entry(object, data)
132    }
133}
134
135/// A simpler entity binding where key and value types are distinct and the
136/// entity is the pair `(K, V)`.
137///
138/// This avoids requiring closure-based extraction by working directly with
139/// tuples.
140pub struct TupleSerdeKeyDataBinding<K, V> {
141    _phantom: PhantomData<(K, V)>,
142}
143
144impl<K, V> TupleSerdeKeyDataBinding<K, V> {
145    /// Creates a new key-data binding.
146    pub fn new() -> Self {
147        Self { _phantom: PhantomData }
148    }
149}
150
151impl<K, V> Default for TupleSerdeKeyDataBinding<K, V> {
152    fn default() -> Self {
153        Self::new()
154    }
155}
156
157impl<K, V> Clone for TupleSerdeKeyDataBinding<K, V> {
158    fn clone(&self) -> Self {
159        Self::new()
160    }
161}
162
163impl<K, V> std::fmt::Debug for TupleSerdeKeyDataBinding<K, V> {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        f.debug_struct("TupleSerdeKeyDataBinding")
166            .field("key_type", &std::any::type_name::<K>())
167            .field("value_type", &std::any::type_name::<V>())
168            .finish()
169    }
170}
171
172impl<K, V> EntityBinding<(K, V)> for TupleSerdeKeyDataBinding<K, V>
173where
174    K: SortKey + Clone,
175    V: Serialize + DeserializeOwned + Clone,
176{
177    fn entry_to_object(
178        &self,
179        key: &DatabaseEntry,
180        data: &DatabaseEntry,
181    ) -> Result<(K, V)> {
182        let mut inp = TupleInput::new(key.data());
183        let k = K::decode_sort_key(&mut inp)?;
184        let data_binding = SerdeBinding::<V>::new();
185        let v = data_binding.entry_to_object(data)?;
186        Ok((k, v))
187    }
188
189    fn object_to_key(
190        &self,
191        object: &(K, V),
192        key: &mut DatabaseEntry,
193    ) -> Result<()> {
194        let mut out = TupleOutput::new();
195        object.0.encode_sort_key(&mut out);
196        key.set_data_vec(out.into_vec());
197        Ok(())
198    }
199
200    fn object_to_data(
201        &self,
202        object: &(K, V),
203        data: &mut DatabaseEntry,
204    ) -> Result<()> {
205        let data_binding = SerdeBinding::<V>::new();
206        data_binding.object_to_entry(&object.1, data)
207    }
208}
209
210#[cfg(test)]
211mod tests {
212    use super::*;
213    use serde::{Deserialize, Serialize};
214
215    #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
216    struct Employee {
217        id: u64,
218        name: String,
219        department: String,
220    }
221
222    #[test]
223    fn test_tuple_serde_binding_round_trip() {
224        let binding = TupleSerdeBinding::<u64, Employee>::new(
225            |emp| emp.id,
226            |_key, data| data,
227        );
228
229        let emp = Employee {
230            id: 42,
231            name: "Alice".to_string(),
232            department: "Engineering".to_string(),
233        };
234
235        let mut key_entry = DatabaseEntry::new();
236        let mut data_entry = DatabaseEntry::new();
237
238        binding.object_to_key(&emp, &mut key_entry).unwrap();
239        binding.object_to_data(&emp, &mut data_entry).unwrap();
240
241        let decoded = binding.entry_to_object(&key_entry, &data_entry).unwrap();
242        assert_eq!(decoded, emp);
243    }
244
245    #[test]
246    fn test_tuple_serde_binding_key_extraction() {
247        let binding = TupleSerdeBinding::<u64, Employee>::new(
248            |emp| emp.id,
249            |_key, data| data,
250        );
251
252        let emp = Employee {
253            id: 99,
254            name: "Bob".to_string(),
255            department: "Sales".to_string(),
256        };
257
258        let mut key_entry = DatabaseEntry::new();
259        binding.object_to_key(&emp, &mut key_entry).unwrap();
260
261        // Decode using TupleInput (sort-preserving big-endian encoding).
262        let mut inp = TupleInput::new(key_entry.data());
263        let key: u64 = u64::decode_sort_key(&mut inp).unwrap();
264        assert_eq!(key, 99);
265    }
266
267    /// Verify that encoded u64 keys are exactly 8 bytes (fixed-width big-endian).
268    #[test]
269    fn test_u64_key_is_8_bytes_fixed_width() {
270        let binding = TupleSerdeBinding::<u64, Employee>::new(
271            |emp| emp.id,
272            |_key, data| data,
273        );
274        for id in [0u64, 1, 2, 10, 100, u64::MAX] {
275            let emp =
276                Employee { id, name: String::new(), department: String::new() };
277            let mut key_entry = DatabaseEntry::new();
278            binding.object_to_key(&emp, &mut key_entry).unwrap();
279            assert_eq!(
280                key_entry.data().len(),
281                8,
282                "u64 key must be 8 bytes (id={})",
283                id
284            );
285        }
286    }
287
288    /// The primary correctness guarantee: lexicographic byte order of encoded
289    /// u64 keys matches numeric order.
290    #[test]
291    fn test_u64_key_sort_order_preserved() {
292        let binding = TupleSerdeBinding::<u64, Employee>::new(
293            |emp| emp.id,
294            |_key, data| data,
295        );
296
297        let key_bytes = |id: u64| {
298            let emp =
299                Employee { id, name: String::new(), department: String::new() };
300            let mut key_entry = DatabaseEntry::new();
301            binding.object_to_key(&emp, &mut key_entry).unwrap();
302            key_entry.get_data().unwrap().to_vec()
303        };
304
305        let b0 = key_bytes(0);
306        let b1 = key_bytes(1);
307        let b2 = key_bytes(2);
308        let b10 = key_bytes(10);
309        let bmax = key_bytes(u64::MAX);
310
311        assert!(b0 < b1, "0 < 1");
312        assert!(b1 < b2, "1 < 2");
313        assert!(b2 < b10, "2 < 10");
314        assert!(b10 < bmax, "10 < MAX");
315    }
316
317    /// i64 keys should sort with negatives before zero before positives.
318    #[test]
319    fn test_i64_key_sort_order_preserved() {
320        let binding = TupleSerdeBinding::<i64, Employee>::new(
321            |emp| emp.id as i64,
322            |_key, data| data,
323        );
324
325        let key_bytes = |id: i64| {
326            let emp = Employee {
327                id: id as u64,
328                name: String::new(),
329                department: String::new(),
330            };
331            let mut key_entry = DatabaseEntry::new();
332            binding.object_to_key(&emp, &mut key_entry).unwrap();
333            key_entry.get_data().unwrap().to_vec()
334        };
335
336        let vals = [i64::MIN, -1000i64, -1, 0, 1, 1000, i64::MAX];
337        for w in vals.windows(2) {
338            assert!(
339                key_bytes(w[0]) < key_bytes(w[1]),
340                "i64 sort order: {} should be < {}",
341                w[0],
342                w[1]
343            );
344        }
345    }
346
347    /// String keys sort lexicographically.
348    #[test]
349    fn test_string_key_sort_order_preserved() {
350        let binding = TupleSerdeBinding::<String, Employee>::new(
351            |emp| emp.name.clone(),
352            |_key, data| data,
353        );
354
355        let key_bytes = |name: &str| {
356            let emp = Employee {
357                id: 0,
358                name: name.to_string(),
359                department: String::new(),
360            };
361            let mut key_entry = DatabaseEntry::new();
362            binding.object_to_key(&emp, &mut key_entry).unwrap();
363            key_entry.get_data().unwrap().to_vec()
364        };
365
366        assert!(key_bytes("a") < key_bytes("b"));
367        assert!(key_bytes("abc") < key_bytes("abd"));
368        assert!(key_bytes("a") < key_bytes("aa"));
369        assert!(key_bytes("") < key_bytes("a"));
370    }
371
372    #[test]
373    fn test_key_data_binding_round_trip() {
374        let binding = TupleSerdeKeyDataBinding::<u32, String>::new();
375
376        let entity = (42u32, "hello".to_string());
377        let mut key_entry = DatabaseEntry::new();
378        let mut data_entry = DatabaseEntry::new();
379
380        binding.object_to_key(&entity, &mut key_entry).unwrap();
381        binding.object_to_data(&entity, &mut data_entry).unwrap();
382
383        let decoded = binding.entry_to_object(&key_entry, &data_entry).unwrap();
384        assert_eq!(decoded, entity);
385    }
386
387    /// u32 keys in TupleSerdeKeyDataBinding sort correctly.
388    #[test]
389    fn test_key_data_binding_u32_sort_order() {
390        let binding = TupleSerdeKeyDataBinding::<u32, String>::new();
391
392        let key_bytes = |k: u32| {
393            let entity = (k, String::new());
394            let mut key_entry = DatabaseEntry::new();
395            binding.object_to_key(&entity, &mut key_entry).unwrap();
396            key_entry.get_data().unwrap().to_vec()
397        };
398
399        let vals = [0u32, 1, 2, 10, 100, 1000, u32::MAX];
400        for w in vals.windows(2) {
401            assert!(
402                key_bytes(w[0]) < key_bytes(w[1]),
403                "{} should sort before {}",
404                w[0],
405                w[1]
406            );
407        }
408    }
409
410    #[test]
411    fn test_key_data_binding_with_struct() {
412        #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
413        struct Product {
414            name: String,
415            price: f64,
416        }
417
418        let binding = TupleSerdeKeyDataBinding::<u64, Product>::new();
419
420        let entity =
421            (100u64, Product { name: "Widget".to_string(), price: 9.99 });
422
423        let mut key_entry = DatabaseEntry::new();
424        let mut data_entry = DatabaseEntry::new();
425
426        binding.object_to_key(&entity, &mut key_entry).unwrap();
427        binding.object_to_data(&entity, &mut data_entry).unwrap();
428
429        let decoded = binding.entry_to_object(&key_entry, &data_entry).unwrap();
430        assert_eq!(decoded, entity);
431    }
432
433    #[test]
434    fn test_key_data_binding_default() {
435        let binding = TupleSerdeKeyDataBinding::<u32, String>::default();
436        let entity = (1u32, "test".to_string());
437        let mut key_entry = DatabaseEntry::new();
438        let mut data_entry = DatabaseEntry::new();
439        binding.object_to_key(&entity, &mut key_entry).unwrap();
440        binding.object_to_data(&entity, &mut data_entry).unwrap();
441        let decoded = binding.entry_to_object(&key_entry, &data_entry).unwrap();
442        assert_eq!(decoded, entity);
443    }
444
445    #[test]
446    fn test_key_data_binding_clone() {
447        let binding = TupleSerdeKeyDataBinding::<u32, String>::new();
448        let cloned = binding.clone();
449        let entity = (7u32, "clone".to_string());
450        let mut key_entry = DatabaseEntry::new();
451        let mut data_entry = DatabaseEntry::new();
452        binding.object_to_key(&entity, &mut key_entry).unwrap();
453        binding.object_to_data(&entity, &mut data_entry).unwrap();
454        let decoded = cloned.entry_to_object(&key_entry, &data_entry).unwrap();
455        assert_eq!(decoded, entity);
456    }
457
458    #[test]
459    fn test_key_data_binding_debug() {
460        let binding = TupleSerdeKeyDataBinding::<u32, String>::new();
461        let debug = format!("{:?}", binding);
462        assert!(debug.contains("TupleSerdeKeyDataBinding"));
463    }
464
465    #[test]
466    fn test_tuple_serde_binding_debug() {
467        let binding = TupleSerdeBinding::<u64, Employee>::new(
468            |emp| emp.id,
469            |_key, data| data,
470        );
471        let debug = format!("{:?}", binding);
472        assert!(debug.contains("TupleSerdeBinding"));
473    }
474
475    #[test]
476    fn test_key_data_with_option_value() {
477        let binding = TupleSerdeKeyDataBinding::<String, Option<u64>>::new();
478        let entity = ("key".to_string(), Some(42u64));
479        let mut key_entry = DatabaseEntry::new();
480        let mut data_entry = DatabaseEntry::new();
481        binding.object_to_key(&entity, &mut key_entry).unwrap();
482        binding.object_to_data(&entity, &mut data_entry).unwrap();
483        let decoded = binding.entry_to_object(&key_entry, &data_entry).unwrap();
484        assert_eq!(decoded, entity);
485    }
486
487    #[test]
488    fn test_key_data_with_vec_value() {
489        let binding = TupleSerdeKeyDataBinding::<u32, Vec<String>>::new();
490        let entity = (1u32, vec!["a".to_string(), "b".to_string()]);
491        let mut key_entry = DatabaseEntry::new();
492        let mut data_entry = DatabaseEntry::new();
493        binding.object_to_key(&entity, &mut key_entry).unwrap();
494        binding.object_to_data(&entity, &mut data_entry).unwrap();
495        let decoded = binding.entry_to_object(&key_entry, &data_entry).unwrap();
496        assert_eq!(decoded, entity);
497    }
498
499    #[test]
500    fn test_entity_creator_transforms() {
501        let binding = TupleSerdeBinding::<u64, Employee>::new(
502            |emp| emp.id,
503            |key, mut data| {
504                data.id = key;
505                data
506            },
507        );
508
509        let emp = Employee {
510            id: 42,
511            name: "Test".to_string(),
512            department: "Eng".to_string(),
513        };
514
515        let mut key_entry = DatabaseEntry::new();
516        let mut data_entry = DatabaseEntry::new();
517        binding.object_to_key(&emp, &mut key_entry).unwrap();
518        binding.object_to_data(&emp, &mut data_entry).unwrap();
519
520        let decoded = binding.entry_to_object(&key_entry, &data_entry).unwrap();
521        assert_eq!(decoded.id, 42);
522        assert_eq!(decoded.name, "Test");
523    }
524
525    /// Verify that u32 key bytes are exactly 4 bytes fixed-width big-endian.
526    #[test]
527    fn test_u32_key_is_4_bytes_fixed_width() {
528        let binding = TupleSerdeKeyDataBinding::<u32, String>::new();
529        for k in [0u32, 1, 255, 256, u32::MAX] {
530            let entity = (k, String::new());
531            let mut key_entry = DatabaseEntry::new();
532            binding.object_to_key(&entity, &mut key_entry).unwrap();
533            assert_eq!(
534                key_entry.data().len(),
535                4,
536                "u32 key must be 4 bytes (k={})",
537                k
538            );
539        }
540    }
541}