Skip to main content

llkv_btree/codecs/
mod.rs

1//! Codecs: key and id encoding/decoding and order-compat comparisons.
2
3use crate::errors::Error;
4use core::cmp::Ordering;
5use core::fmt::Debug;
6use core::hash::Hash;
7use std::str;
8
9// --- Traits ---
10
11// TODO: Rename to connotate "physical" & "logical" keys? This would also involve renaming of `KeyCodec` and `IdCodec`
12pub trait KeyCodec {
13    type Key: Clone + Ord + Debug;
14    fn encoded_len(key: &Self::Key) -> usize;
15    fn encode_into(key: &Self::Key, out: &mut Vec<u8>);
16    fn decode_from(bytes: &[u8]) -> Result<Self::Key, Error>;
17    fn compare_encoded(encoded: &[u8], key: &Self::Key) -> Ordering;
18    fn cmp_enc_vs_enc(a: &[u8], b: &[u8]) -> Ordering;
19}
20
21pub trait IdCodec {
22    type Id: Clone + Eq + Ord + Hash + Debug;
23    fn encoded_len(id: &Self::Id) -> usize;
24    fn encode_into(id: &Self::Id, out: &mut Vec<u8>);
25    fn decode_from(bytes: &[u8]) -> Result<(Self::Id, usize), Error>;
26}
27
28// --- Generic Integer Codec ---
29
30/// A generic codec for any integer type that can be represented as big-endian bytes.
31#[derive(Debug)]
32pub struct BigEndianKeyCodec<T>(std::marker::PhantomData<T>);
33pub struct BigEndianIdCodec<T>(std::marker::PhantomData<T>);
34
35// Define the necessary trait bounds for integers we can handle.
36pub trait Int: Sized + Copy + Ord + Debug + Hash {
37    type Bytes: AsRef<[u8]> + AsMut<[u8]> + for<'a> TryFrom<&'a [u8]>;
38    fn to_be_bytes(self) -> Self::Bytes;
39    fn from_be_bytes(bytes: Self::Bytes) -> Self;
40}
41
42impl Int for u32 {
43    type Bytes = [u8; 4];
44    fn to_be_bytes(self) -> Self::Bytes {
45        self.to_be_bytes()
46    }
47    fn from_be_bytes(bytes: Self::Bytes) -> Self {
48        Self::from_be_bytes(bytes)
49    }
50}
51impl Int for u64 {
52    type Bytes = [u8; 8];
53    fn to_be_bytes(self) -> Self::Bytes {
54        self.to_be_bytes()
55    }
56    fn from_be_bytes(bytes: Self::Bytes) -> Self {
57        Self::from_be_bytes(bytes)
58    }
59}
60impl Int for u128 {
61    type Bytes = [u8; 16];
62    fn to_be_bytes(self) -> Self::Bytes {
63        self.to_be_bytes()
64    }
65    fn from_be_bytes(bytes: Self::Bytes) -> Self {
66        Self::from_be_bytes(bytes)
67    }
68}
69
70// --- Implementations ---
71
72impl<T: Int> KeyCodec for BigEndianKeyCodec<T>
73where
74    T::Bytes: Debug,
75    for<'a> <T::Bytes as TryFrom<&'a [u8]>>::Error: Debug,
76{
77    type Key = T;
78
79    fn encoded_len(_: &Self::Key) -> usize {
80        std::mem::size_of::<T>()
81    }
82    fn encode_into(key: &Self::Key, out: &mut Vec<u8>) {
83        out.extend_from_slice(key.to_be_bytes().as_ref());
84    }
85    fn decode_from(bytes: &[u8]) -> Result<Self::Key, Error> {
86        let array = bytes
87            .try_into()
88            .map_err(|_| Error::Corrupt("invalid int bytes"))?;
89        Ok(T::from_be_bytes(array))
90    }
91    fn compare_encoded(encoded: &[u8], key: &Self::Key) -> Ordering {
92        let decoded = T::from_be_bytes(encoded.try_into().unwrap());
93        decoded.cmp(key)
94    }
95    fn cmp_enc_vs_enc(a: &[u8], b: &[u8]) -> Ordering {
96        a.cmp(b)
97    }
98}
99
100impl<T: Int> IdCodec for BigEndianIdCodec<T>
101where
102    T::Bytes: Debug,
103    for<'a> <T::Bytes as TryFrom<&'a [u8]>>::Error: Debug,
104{
105    type Id = T;
106
107    fn encoded_len(_: &Self::Id) -> usize {
108        std::mem::size_of::<T>()
109    }
110    fn encode_into(id: &Self::Id, out: &mut Vec<u8>) {
111        out.extend_from_slice(id.to_be_bytes().as_ref());
112    }
113    fn decode_from(bytes: &[u8]) -> Result<(Self::Id, usize), Error> {
114        let len = std::mem::size_of::<T>();
115        let array = bytes[..len]
116            .try_into()
117            .map_err(|_| Error::Corrupt("invalid int bytes"))?;
118        let val = T::from_be_bytes(array);
119        Ok((val, len))
120    }
121}
122
123/// A codec for `String` keys that uses UTF-8 byte representation.
124pub struct StringKeyCodec;
125impl KeyCodec for StringKeyCodec {
126    type Key = String;
127    fn encoded_len(key: &Self::Key) -> usize {
128        key.len()
129    }
130    fn encode_into(key: &Self::Key, out: &mut Vec<u8>) {
131        out.extend_from_slice(key.as_bytes());
132    }
133    fn decode_from(bytes: &[u8]) -> Result<Self::Key, Error> {
134        str::from_utf8(bytes)
135            .map(|s| s.to_string())
136            .map_err(|_| Error::Corrupt("invalid utf8"))
137    }
138    fn compare_encoded(encoded: &[u8], key: &Self::Key) -> Ordering {
139        str::from_utf8(encoded).unwrap().cmp(key)
140    }
141    fn cmp_enc_vs_enc(a: &[u8], b: &[u8]) -> Ordering {
142        a.cmp(b)
143    }
144}
145
146#[inline]
147pub fn read_u32_at(b: &[u8], pos: usize) -> (u32, usize) {
148    let n = u32::from_le_bytes(b[pos..pos + 4].try_into().unwrap());
149    (n, pos + 4)
150}
151#[inline]
152pub fn push_u32(out: &mut Vec<u8>, x: u32) {
153    out.extend_from_slice(&x.to_le_bytes());
154}