reifydb_core/value/encoded/
key.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the AGPL-3.0-or-later, see license.md file
3
4use std::{
5	collections::{
6		Bound,
7		Bound::{Excluded, Included, Unbounded},
8	},
9	ops::{Deref, RangeBounds},
10};
11
12use serde::{Deserialize, Serialize};
13
14use crate::util::{
15	CowVec,
16	encoding::{binary::decode_binary, keycode::KeySerializer},
17};
18
19#[derive(Debug, Clone, PartialOrd, Ord, Hash, PartialEq, Eq, Serialize, Deserialize)]
20pub struct EncodedKey(pub CowVec<u8>);
21
22impl Deref for EncodedKey {
23	type Target = CowVec<u8>;
24
25	fn deref(&self) -> &Self::Target {
26		&self.0
27	}
28}
29
30impl EncodedKey {
31	pub fn new(key: impl Into<Vec<u8>>) -> Self {
32		Self(CowVec::new(key.into()))
33	}
34
35	pub fn as_bytes(&self) -> &[u8] {
36		self.0.as_ref()
37	}
38
39	pub fn as_slice(&self) -> &[u8] {
40		self.0.as_ref()
41	}
42}
43
44/// Trait for types that can be converted into an EncodedKey.
45/// Provides convenient conversions from common types to EncodedKey using proper order-preserving encoding.
46pub trait IntoEncodedKey {
47	fn into_encoded_key(self) -> EncodedKey;
48}
49
50// Direct passthrough for EncodedKey
51impl IntoEncodedKey for EncodedKey {
52	fn into_encoded_key(self) -> EncodedKey {
53		self
54	}
55}
56
57// String types - using extend_str for proper encoding
58impl IntoEncodedKey for &str {
59	fn into_encoded_key(self) -> EncodedKey {
60		let mut serializer = KeySerializer::new();
61		serializer.extend_str(self);
62		serializer.to_encoded_key()
63	}
64}
65
66impl IntoEncodedKey for String {
67	fn into_encoded_key(self) -> EncodedKey {
68		let mut serializer = KeySerializer::new();
69		serializer.extend_str(&self);
70		serializer.to_encoded_key()
71	}
72}
73
74// Byte arrays - using extend_bytes for escaped encoding
75impl IntoEncodedKey for Vec<u8> {
76	fn into_encoded_key(self) -> EncodedKey {
77		let mut serializer = KeySerializer::new();
78		serializer.extend_bytes(&self);
79		serializer.to_encoded_key()
80	}
81}
82
83impl IntoEncodedKey for &[u8] {
84	fn into_encoded_key(self) -> EncodedKey {
85		let mut serializer = KeySerializer::new();
86		serializer.extend_bytes(self);
87		serializer.to_encoded_key()
88	}
89}
90
91// Numeric types - using proper encoding for order preservation
92impl IntoEncodedKey for u64 {
93	fn into_encoded_key(self) -> EncodedKey {
94		let mut serializer = KeySerializer::with_capacity(8);
95		serializer.extend_u64(self);
96		serializer.to_encoded_key()
97	}
98}
99
100impl IntoEncodedKey for i64 {
101	fn into_encoded_key(self) -> EncodedKey {
102		let mut serializer = KeySerializer::with_capacity(8);
103		serializer.extend_i64(self);
104		serializer.to_encoded_key()
105	}
106}
107
108impl IntoEncodedKey for u32 {
109	fn into_encoded_key(self) -> EncodedKey {
110		let mut serializer = KeySerializer::with_capacity(4);
111		serializer.extend_u32(self);
112		serializer.to_encoded_key()
113	}
114}
115
116impl IntoEncodedKey for i32 {
117	fn into_encoded_key(self) -> EncodedKey {
118		let mut serializer = KeySerializer::with_capacity(4);
119		serializer.extend_i32(self);
120		serializer.to_encoded_key()
121	}
122}
123
124impl IntoEncodedKey for u16 {
125	fn into_encoded_key(self) -> EncodedKey {
126		let mut serializer = KeySerializer::with_capacity(2);
127		serializer.extend_u16(self);
128		serializer.to_encoded_key()
129	}
130}
131
132impl IntoEncodedKey for i16 {
133	fn into_encoded_key(self) -> EncodedKey {
134		let mut serializer = KeySerializer::with_capacity(2);
135		serializer.extend_i16(self);
136		serializer.to_encoded_key()
137	}
138}
139
140impl IntoEncodedKey for u8 {
141	fn into_encoded_key(self) -> EncodedKey {
142		let mut serializer = KeySerializer::with_capacity(1);
143		serializer.extend_u8(self);
144		serializer.to_encoded_key()
145	}
146}
147
148impl IntoEncodedKey for i8 {
149	fn into_encoded_key(self) -> EncodedKey {
150		let mut serializer = KeySerializer::with_capacity(1);
151		serializer.extend_i8(self);
152		serializer.to_encoded_key()
153	}
154}
155
156#[derive(Clone, Debug)]
157pub struct EncodedKeyRange {
158	pub start: Bound<EncodedKey>,
159	pub end: Bound<EncodedKey>,
160}
161
162impl EncodedKeyRange {
163	pub fn new(start: Bound<EncodedKey>, end: Bound<EncodedKey>) -> Self {
164		Self {
165			start,
166			end,
167		}
168	}
169
170	/// Generates a key range for a key prefix, used e.g. for prefix scans.
171	///
172	/// The exclusive end bound is generated by adding 1 to the value of the
173	/// last byte. If the last byte(s) is 0xff (so adding 1 would
174	/// saturation), we instead find the latest non-0xff byte, increment
175	/// that, and truncate the rest. If all bytes are 0xff, we scan to the
176	/// end of the range, since there can't be other prefixes after it.
177	pub fn prefix(prefix: &[u8]) -> Self {
178		let start = Bound::Included(EncodedKey::new(prefix));
179		let end = match prefix.iter().rposition(|&b| b != 0xff) {
180			Some(i) => Bound::Excluded(EncodedKey::new(
181				prefix.iter()
182					.take(i)
183					.copied()
184					.chain(std::iter::once(prefix[i] + 1))
185					.collect::<Vec<_>>(),
186			)),
187			None => Bound::Unbounded,
188		};
189		Self {
190			start,
191			end,
192		}
193	}
194
195	pub fn with_prefix(&self, prefix: EncodedKey) -> Self {
196		let start = match self.start_bound() {
197			Included(key) => {
198				let mut prefixed = Vec::with_capacity(prefix.len() + key.len());
199				prefixed.extend_from_slice(prefix.as_ref());
200				prefixed.extend_from_slice(key.as_ref());
201				Included(EncodedKey::new(prefixed))
202			}
203			Excluded(key) => {
204				let mut prefixed = Vec::with_capacity(prefix.len() + key.len());
205				prefixed.extend_from_slice(prefix.as_ref());
206				prefixed.extend_from_slice(key.as_ref());
207				Excluded(EncodedKey::new(prefixed))
208			}
209			Unbounded => Included(prefix.clone()),
210		};
211
212		let end = match self.end_bound() {
213			Included(key) => {
214				let mut prefixed = Vec::with_capacity(prefix.len() + key.len());
215				prefixed.extend_from_slice(prefix.as_ref());
216				prefixed.extend_from_slice(key.as_ref());
217				Included(EncodedKey::new(prefixed))
218			}
219			Excluded(key) => {
220				let mut prefixed = Vec::with_capacity(prefix.len() + key.len());
221				prefixed.extend_from_slice(prefix.as_ref());
222				prefixed.extend_from_slice(key.as_ref());
223				Excluded(EncodedKey::new(prefixed))
224			}
225			Unbounded => match prefix.as_ref().iter().rposition(|&b| b != 0xff) {
226				Some(i) => {
227					let mut next_prefix = prefix.as_ref()[..=i].to_vec();
228					next_prefix[i] += 1;
229					Excluded(EncodedKey::new(next_prefix))
230				}
231				None => Unbounded,
232			},
233		};
234
235		EncodedKeyRange::new(start, end)
236	}
237
238	/// Constructs a key range from an optional inclusive start key to an
239	/// optional inclusive end key.
240	///
241	/// - `start`: If provided, marks the inclusive lower bound of the range. If `None`, the range is unbounded
242	///   below.
243	/// - `end`: If provided, marks the inclusive upper bound of the range. If `None`, the range is unbounded above.
244	///
245	/// This function does not modify the input keys and assumes they are
246	/// already exact keys (not prefixes). If you need to scan all keys
247	/// with a given prefix, use [`EncodedKeyRange::prefix`] instead.
248	///
249	/// Useful for scanning between two explicit keys in a sorted key-value
250	/// store.
251	pub fn start_end(start: Option<EncodedKey>, end: Option<EncodedKey>) -> Self {
252		let start = match start {
253			Some(s) => Bound::Included(s),
254			None => Bound::Unbounded,
255		};
256
257		let end = match end {
258			Some(e) => Bound::Included(e),
259			None => Bound::Unbounded,
260		};
261
262		Self {
263			start,
264			end,
265		}
266	}
267
268	/// Constructs a key range that fragments the entire keyspace.
269	///
270	/// This range has no lower or upper bounds, making it suitable for full
271	/// scans over all keys in a sorted key-value store.
272	///
273	/// Equivalent to: `..` (in Rust range syntax)
274	pub fn all() -> Self {
275		Self {
276			start: Bound::Unbounded,
277			end: Bound::Unbounded,
278		}
279	}
280
281	/// Parses a human-readable range string into a `KeyRange`.
282	///
283	/// The expected format is `<start>..[=]<end>`, where:
284	/// - `<start>` is the inclusive lower bound (optional),
285	/// - `..` separates the bounds,
286	/// - `=` after `..` makes the upper bound inclusive,
287	/// - `<end>` is the upper bound (optional).
288	///
289	/// Examples:
290	/// - `"a..z"`       => start = Included("a"), end = Excluded("z")
291	/// - `"a..=z"`      => start = Included("a"), end = Included("z")
292	/// - `"..z"`        => start = Unbounded,     end = Excluded("z")
293	/// - `"a.."`        => start = Included("a"), end = Unbounded
294	///
295	/// If parsing fails, it defaults to a degenerate range from `0xff` to
296	/// `0xff` (empty).
297	pub fn parse(str: &str) -> Self {
298		let (mut start, mut end) = (Bound::<EncodedKey>::Unbounded, Bound::<EncodedKey>::Unbounded);
299
300		// Find the ".." separator
301		if let Some(dot_pos) = str.find("..") {
302			let start_part = &str[..dot_pos];
303			let end_part = &str[dot_pos + 2..];
304
305			// Parse start bound
306			if !start_part.is_empty() {
307				start = Bound::Included(EncodedKey(decode_binary(start_part)));
308			}
309
310			// Parse end bound - check for inclusive marker "="
311			if let Some(end_str) = end_part.strip_prefix('=') {
312				// Inclusive end: "..="
313				if !end_str.is_empty() {
314					end = Bound::Included(EncodedKey(decode_binary(end_str)));
315				}
316			} else {
317				// Exclusive end: ".."
318				if !end_part.is_empty() {
319					end = Bound::Excluded(EncodedKey(decode_binary(end_part)));
320				}
321			}
322
323			Self {
324				start,
325				end,
326			}
327		} else {
328			// Invalid format - return degenerate range
329			Self {
330				start: Bound::Included(EncodedKey::new([0xff])),
331				end: Bound::Excluded(EncodedKey::new([0xff])),
332			}
333		}
334	}
335}
336
337impl RangeBounds<EncodedKey> for EncodedKeyRange {
338	fn start_bound(&self) -> Bound<&EncodedKey> {
339		self.start.as_ref()
340	}
341
342	fn end_bound(&self) -> Bound<&EncodedKey> {
343		self.end.as_ref()
344	}
345}
346
347#[cfg(test)]
348mod tests {
349	use std::collections::Bound;
350
351	use super::EncodedKey;
352
353	macro_rules! as_key {
354		($key:expr) => {{ EncodedKey::new(keycode::serialize(&$key)) }};
355	}
356
357	mod prefix {
358		use std::ops::Bound;
359
360		use crate::value::encoded::key::{
361			EncodedKeyRange,
362			tests::{excluded, included},
363		};
364
365		#[test]
366		fn test_simple() {
367			let range = EncodedKeyRange::prefix(&[0x12, 0x34]);
368			assert_eq!(range.start, included(&[0x12, 0x34]));
369			assert_eq!(range.end, excluded(&[0x12, 0x35]));
370		}
371
372		#[test]
373		fn test_with_trailing_ff() {
374			let range = EncodedKeyRange::prefix(&[0x12, 0xff]);
375			assert_eq!(range.start, included(&[0x12, 0xff]));
376			assert_eq!(range.end, excluded(&[0x13]));
377		}
378
379		#[test]
380		fn test_with_multiple_trailing_ff() {
381			let range = EncodedKeyRange::prefix(&[0x12, 0xff, 0xff]);
382			assert_eq!(range.start, included(&[0x12, 0xff, 0xff]));
383			assert_eq!(range.end, excluded(&[0x13]));
384		}
385
386		#[test]
387		fn test_all_ff() {
388			let range = EncodedKeyRange::prefix(&[0xff, 0xff]);
389			assert_eq!(range.start, included(&[0xff, 0xff]));
390			assert_eq!(range.end, Bound::Unbounded);
391		}
392
393		#[test]
394		fn test_empty() {
395			let range = EncodedKeyRange::prefix(&[]);
396			assert_eq!(range.start, included(&[]));
397			assert_eq!(range.end, Bound::Unbounded);
398		}
399
400		#[test]
401		fn test_mid_increment() {
402			let range = EncodedKeyRange::prefix(&[0x12, 0x00, 0xff]);
403			assert_eq!(range.start, included(&[0x12, 0x00, 0xff]));
404			assert_eq!(range.end, excluded(&[0x12, 0x01]));
405		}
406	}
407
408	mod start_end {
409		use std::ops::Bound;
410
411		use crate::{
412			EncodedKey,
413			util::encoding::keycode,
414			value::encoded::key::{EncodedKeyRange, tests::included},
415		};
416
417		#[test]
418		fn test_start_and_end() {
419			let range = EncodedKeyRange::start_end(Some(as_key!(1)), Some(as_key!(2)));
420			assert_eq!(range.start, included(&as_key!(1)));
421			assert_eq!(range.end, included(&as_key!(2)));
422		}
423
424		#[test]
425		fn test_start_only() {
426			let range = EncodedKeyRange::start_end(Some(as_key!(1)), None);
427			assert_eq!(range.start, included(&as_key!(1)));
428			assert_eq!(range.end, Bound::Unbounded);
429		}
430
431		#[test]
432		fn test_end_only() {
433			let range = EncodedKeyRange::start_end(None, Some(as_key!(2)));
434			assert_eq!(range.start, Bound::Unbounded);
435			assert_eq!(range.end, included(&as_key!(2)));
436		}
437
438		#[test]
439		fn test_unbounded_range() {
440			let range = EncodedKeyRange::start_end(None, None);
441			assert_eq!(range.start, Bound::Unbounded);
442			assert_eq!(range.end, Bound::Unbounded);
443		}
444
445		#[test]
446		fn test_full_byte_range() {
447			let range = EncodedKeyRange::start_end(Some(as_key!(0x00)), Some(as_key!(0xff)));
448			assert_eq!(range.start, included(&as_key!(0x00)));
449			assert_eq!(range.end, included(&as_key!(0xff)));
450		}
451
452		#[test]
453		fn test_identical_bounds() {
454			let range = EncodedKeyRange::start_end(Some(as_key!(0x42)), Some(as_key!(0x42)));
455			assert_eq!(range.start, included(&as_key!(0x42)));
456			assert_eq!(range.end, included(&as_key!(0x42)));
457		}
458	}
459
460	mod all {
461		use std::ops::Bound;
462
463		use crate::value::encoded::key::EncodedKeyRange;
464
465		#[test]
466		fn test_is_unbounded() {
467			let range = EncodedKeyRange::all();
468			assert_eq!(range.start, Bound::Unbounded);
469			assert_eq!(range.end, Bound::Unbounded);
470		}
471	}
472
473	mod parse {
474		use std::ops::Bound;
475
476		use crate::value::encoded::key::{
477			EncodedKey, EncodedKeyRange,
478			tests::{excluded, included},
479		};
480
481		#[test]
482		fn test_full_range() {
483			let r = EncodedKeyRange::parse("a..z");
484			assert_eq!(r.start, included(b"a"));
485			assert_eq!(r.end, excluded(b"z"));
486		}
487
488		#[test]
489		fn test_inclusive_end() {
490			let r = EncodedKeyRange::parse("a..=z");
491			assert_eq!(r.start, included(b"a"));
492			assert_eq!(r.end, included(b"z"));
493		}
494
495		#[test]
496		fn test_unbounded_start() {
497			let r = EncodedKeyRange::parse("..z");
498			assert_eq!(r.start, Bound::Unbounded);
499			assert_eq!(r.end, excluded(b"z"));
500		}
501
502		#[test]
503		fn test_unbounded_end() {
504			let r = EncodedKeyRange::parse("a..");
505			assert_eq!(r.start, included(b"a"));
506			assert_eq!(r.end, Bound::Unbounded);
507		}
508
509		#[test]
510		fn test_inclusive_only() {
511			let r = EncodedKeyRange::parse("..=z");
512			assert_eq!(r.start, Bound::Unbounded);
513			assert_eq!(r.end, included(b"z"));
514		}
515
516		#[test]
517		fn test_invalid_string_returns_degenerate_range() {
518			let r = EncodedKeyRange::parse("not a range");
519			let expected = EncodedKey::new([0xff]);
520			assert_eq!(r.start, Bound::Included(expected.clone()));
521			assert_eq!(r.end, Bound::Excluded(expected));
522		}
523
524		#[test]
525		fn test_empty_string_returns_degenerate_range() {
526			let r = EncodedKeyRange::parse("");
527			let expected = EncodedKey::new([0xff]);
528			assert_eq!(r.start, Bound::Included(expected.clone()));
529			assert_eq!(r.end, Bound::Excluded(expected));
530		}
531
532		#[test]
533		fn test_binary_encoded_values() {
534			let r = EncodedKeyRange::parse("0101..=0aff");
535			// decode_binary("0101") = [0x01, 0x01]
536			assert_eq!(r.start, included(b"0101"));
537			// decode_binary("0aff") = [0x0a, 0xff]
538			assert_eq!(r.end, included(b"0aff"));
539		}
540	}
541
542	fn included(key: &[u8]) -> Bound<EncodedKey> {
543		Bound::Included(EncodedKey::new(key))
544	}
545
546	fn excluded(key: &[u8]) -> Bound<EncodedKey> {
547		Bound::Excluded(EncodedKey::new(key))
548	}
549}