stupid_simple_kv/keys/
mod.rs

1use key_segment::KeySegment;
2pub mod display;
3mod key_decoder;
4mod key_segment;
5
6/// Key type for stupid-simple-kv. Must be order-preserving (lexicographically).
7#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug)]
8pub struct KvKey(pub(crate) Vec<u8>);
9
10impl Default for KvKey {
11    fn default() -> Self {
12        Self::new()
13    }
14}
15
16impl KvKey {
17    pub fn new() -> Self {
18        Self(Vec::with_capacity(128))
19    }
20
21    pub fn push(&mut self, part: &dyn KeySegment) {
22        part.encode_into(&mut self.0);
23    }
24
25    pub fn starts_with(&self, key: &KvKey) -> bool {
26        self.0.starts_with(&key.0)
27    }
28
29    /// Returns the smallest key that is strictly greater than this one.
30    /// Useful for exclusive upper bounds in range queries.
31    pub fn successor(&self) -> Option<KvKey> {
32        let mut bytes = self.0.clone();
33        for i in (0..bytes.len()).rev() {
34            if bytes[i] != 0xFF {
35                bytes[i] += 1;
36                bytes.truncate(i + 1); // next higher key, all bytes after that don't matter
37                return Some(KvKey(bytes));
38            }
39            // else, keep looking left
40        }
41        // All bytes were 0xFF, no higher key possible
42        None
43    }
44}
45
46/// Trait to convert any Rust type or tuple into a key suitable for [`Kv`] operations.
47///
48/// Implemented for `u64`, `i64`, `bool`, `String`, `&str`, [`KvKey`], and upto 16-tuples thereof.
49pub trait IntoKey {
50    fn to_key(&self) -> KvKey;
51}
52
53impl IntoKey for u64 {
54    fn to_key(&self) -> KvKey {
55        let mut key = KvKey::new();
56        key.push(self);
57        key
58    }
59}
60
61impl IntoKey for i64 {
62    fn to_key(&self) -> KvKey {
63        let mut key = KvKey::new();
64        key.push(self);
65        key
66    }
67}
68
69impl IntoKey for String {
70    fn to_key(&self) -> KvKey {
71        let mut key = KvKey::new();
72        key.push(self);
73        key
74    }
75}
76
77impl IntoKey for bool {
78    fn to_key(&self) -> KvKey {
79        let mut key = KvKey::new();
80        key.push(self);
81        key
82    }
83}
84
85impl IntoKey for &str {
86    fn to_key(&self) -> KvKey {
87        let mut key = KvKey::new();
88        key.push(self);
89        key
90    }
91}
92
93impl IntoKey for KvKey {
94    fn to_key(&self) -> KvKey {
95        self.clone()
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use crate::{KvResult, keys::IntoKey};
102
103    // These macros/traits must already be in your crate:
104    //   - impl_kv_key_for_tuple! (for IntoKey)
105    //   - impl_kvkey_tryfrom_tuple! (for TryFrom)
106    //   - KeySegment for u64, String, bool, i64, etc.
107    //   - KeySegmentDecode for those types
108
109    #[test]
110    fn roundtrip_one_tuple() -> KvResult<()> {
111        let tup = (42u64,);
112        let key = tup.to_key();
113        let out: (u64,) = key.try_into()?;
114        assert_eq!(tup, out);
115        Ok(())
116    }
117
118    #[test]
119    fn roundtrip_simple_tuple() -> KvResult<()> {
120        let tup = (1234u64, String::from("hello"));
121        let key = tup.clone().to_key();
122        let out: (u64, String) = key.try_into()?;
123        assert_eq!(tup, out);
124        Ok(())
125    }
126
127    #[test]
128    fn roundtrip_longer_tuple() -> KvResult<()> {
129        let tup = (19u64, -5i64, "foo", true, false);
130        let key = tup.clone().to_key();
131        let out: (u64, i64, String, bool, bool) = key.try_into()?;
132        assert_eq!((tup.0, tup.1, tup.2.to_owned(), tup.3, tup.4), out);
133        Ok(())
134    }
135
136    #[test]
137    fn roundtrip_tuple_tryfrom() -> KvResult<()> {
138        let tup = (7u64, "hello world", true);
139        let key = tup.clone().to_key();
140        let out: (u64, String, bool) = key.try_into()?;
141        assert_eq!((tup.0, tup.1.to_owned(), tup.2), out);
142        Ok(())
143    }
144
145    #[test]
146    fn decode_error_wrong_type() -> KvResult<()> {
147        let tup = (237u64, false);
148        let key = tup.to_key();
149        // Attempt to decode as (bool, u64): type order/encoding mismatch
150        let out: KvResult<(bool, u64)> = key.try_into();
151        assert!(out.is_err());
152        Ok(())
153    }
154
155    #[test]
156    fn decode_error_wrong_length() -> KvResult<()> {
157        let tup = (55u64, "xyz");
158        let key = tup.to_key();
159        // Attempt to decode as a 3-tuple (should fail)
160        let out: KvResult<(u64, String, bool)> = key.try_into();
161        assert!(out.is_err());
162        Ok(())
163    }
164
165    #[test]
166    fn roundtrip_with_strings() -> KvResult<()> {
167        let tup = (999u64, "potato", "apple", true);
168        let key = tup.clone().to_key();
169        let out: (u64, String, String, bool) = key.try_into()?;
170        assert_eq!((tup.0, tup.1.to_owned(), tup.2.to_owned(), tup.3), out);
171        Ok(())
172    }
173
174    #[test]
175    fn roundtrip_false_bool() -> KvResult<()> {
176        let tup = (0u64, false, "z");
177        let key = tup.clone().to_key();
178        let out: (u64, bool, String) = key.try_into()?;
179        assert_eq!((tup.0, tup.1, tup.2.to_owned()), out);
180        Ok(())
181    }
182}