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 reifydb_type::{
13	Blob, Date, DateTime, Decimal, Duration, IdentityId, Int, RowNumber, Time, Uint, Uuid4, Uuid7, Value,
14};
15use serde::{Deserialize, Serialize};
16
17use crate::{
18	interface::{IndexId, SourceId},
19	util::{
20		CowVec,
21		encoding::{binary::decode_binary, keycode::KeySerializer},
22	},
23};
24
25#[derive(Debug, Clone, PartialOrd, Ord, Hash, PartialEq, Eq, Serialize, Deserialize)]
26pub struct EncodedKey(pub CowVec<u8>);
27
28impl Deref for EncodedKey {
29	type Target = CowVec<u8>;
30
31	fn deref(&self) -> &Self::Target {
32		&self.0
33	}
34}
35
36impl AsRef<[u8]> for EncodedKey {
37	fn as_ref(&self) -> &[u8] {
38		self.0.as_ref()
39	}
40}
41
42impl EncodedKey {
43	pub fn new(key: impl Into<Vec<u8>>) -> Self {
44		Self(CowVec::new(key.into()))
45	}
46
47	/// Create a new builder for constructing an EncodedKey
48	pub fn builder() -> EncodedKeyBuilder {
49		EncodedKeyBuilder::new()
50	}
51
52	pub fn as_bytes(&self) -> &[u8] {
53		self.0.as_ref()
54	}
55
56	pub fn as_slice(&self) -> &[u8] {
57		self.0.as_ref()
58	}
59}
60
61/// A builder for constructing EncodedKey values using keycode encoding
62///
63/// This provides a fluent API for building composite keys with proper order-preserving encoding.
64pub struct EncodedKeyBuilder {
65	serializer: KeySerializer,
66}
67
68impl EncodedKeyBuilder {
69	/// Create a new builder
70	pub fn new() -> Self {
71		Self {
72			serializer: KeySerializer::new(),
73		}
74	}
75
76	/// Create a builder with pre-allocated capacity
77	pub fn with_capacity(capacity: usize) -> Self {
78		Self {
79			serializer: KeySerializer::with_capacity(capacity),
80		}
81	}
82
83	/// Build the EncodedKey
84	pub fn build(self) -> EncodedKey {
85		self.serializer.to_encoded_key()
86	}
87
88	/// Extend with bool value
89	pub fn bool(mut self, value: bool) -> Self {
90		self.serializer.extend_bool(value);
91		self
92	}
93
94	/// Extend with f32 value
95	pub fn f32(mut self, value: f32) -> Self {
96		self.serializer.extend_f32(value);
97		self
98	}
99
100	/// Extend with f64 value
101	pub fn f64(mut self, value: f64) -> Self {
102		self.serializer.extend_f64(value);
103		self
104	}
105
106	/// Extend with i8 value
107	pub fn i8<T: Into<i8>>(mut self, value: T) -> Self {
108		self.serializer.extend_i8(value);
109		self
110	}
111
112	/// Extend with i16 value
113	pub fn i16<T: Into<i16>>(mut self, value: T) -> Self {
114		self.serializer.extend_i16(value);
115		self
116	}
117
118	/// Extend with i32 value
119	pub fn i32<T: Into<i32>>(mut self, value: T) -> Self {
120		self.serializer.extend_i32(value);
121		self
122	}
123
124	/// Extend with i64 value
125	pub fn i64<T: Into<i64>>(mut self, value: T) -> Self {
126		self.serializer.extend_i64(value);
127		self
128	}
129
130	/// Extend with i128 value
131	pub fn i128<T: Into<i128>>(mut self, value: T) -> Self {
132		self.serializer.extend_i128(value);
133		self
134	}
135
136	/// Extend with u8 value
137	pub fn u8<T: Into<u8>>(mut self, value: T) -> Self {
138		self.serializer.extend_u8(value);
139		self
140	}
141
142	/// Extend with u16 value
143	pub fn u16<T: Into<u16>>(mut self, value: T) -> Self {
144		self.serializer.extend_u16(value);
145		self
146	}
147
148	/// Extend with u32 value
149	pub fn u32<T: Into<u32>>(mut self, value: T) -> Self {
150		self.serializer.extend_u32(value);
151		self
152	}
153
154	/// Extend with u64 value
155	pub fn u64<T: Into<u64>>(mut self, value: T) -> Self {
156		self.serializer.extend_u64(value);
157		self
158	}
159
160	/// Extend with u128 value
161	pub fn u128<T: Into<u128>>(mut self, value: T) -> Self {
162		self.serializer.extend_u128(value);
163		self
164	}
165
166	/// Extend with raw bytes (with encoding)
167	pub fn bytes<T: AsRef<[u8]>>(mut self, bytes: T) -> Self {
168		self.serializer.extend_bytes(bytes);
169		self
170	}
171
172	/// Extend with string (UTF-8 bytes)
173	pub fn str<T: AsRef<str>>(mut self, s: T) -> Self {
174		self.serializer.extend_str(s);
175		self
176	}
177
178	/// Extend with a SourceId value
179	pub fn source_id(mut self, source: impl Into<SourceId>) -> Self {
180		self.serializer.extend_source_id(source);
181		self
182	}
183
184	/// Extend with an IndexId value
185	pub fn index_id(mut self, index: impl Into<IndexId>) -> Self {
186		self.serializer.extend_index_id(index);
187		self
188	}
189
190	/// Extend with a serializable value using keycode encoding
191	pub fn serialize<T: Serialize>(mut self, value: &T) -> Self {
192		self.serializer.extend_serialize(value);
193		self
194	}
195
196	/// Extend with raw bytes (no encoding)
197	pub fn raw(mut self, bytes: &[u8]) -> Self {
198		self.serializer.extend_raw(bytes);
199		self
200	}
201
202	/// Get current buffer length
203	pub fn len(&self) -> usize {
204		self.serializer.len()
205	}
206
207	/// Check if buffer is empty
208	pub fn is_empty(&self) -> bool {
209		self.serializer.is_empty()
210	}
211
212	/// Extend with Date value
213	pub fn date(mut self, date: &Date) -> Self {
214		self.serializer.extend_date(date);
215		self
216	}
217
218	/// Extend with DateTime value
219	pub fn datetime(mut self, datetime: &DateTime) -> Self {
220		self.serializer.extend_datetime(datetime);
221		self
222	}
223
224	/// Extend with Time value
225	pub fn time(mut self, time: &Time) -> Self {
226		self.serializer.extend_time(time);
227		self
228	}
229
230	/// Extend with Duration value
231	pub fn duration(mut self, duration: &Duration) -> Self {
232		self.serializer.extend_duration(duration);
233		self
234	}
235
236	/// Extend with RowNumber value
237	pub fn row_number(mut self, row_number: &RowNumber) -> Self {
238		self.serializer.extend_row_number(row_number);
239		self
240	}
241
242	/// Extend with IdentityId value
243	pub fn identity_id(mut self, id: &IdentityId) -> Self {
244		self.serializer.extend_identity_id(id);
245		self
246	}
247
248	/// Extend with Uuid4 value
249	pub fn uuid4(mut self, uuid: &Uuid4) -> Self {
250		self.serializer.extend_uuid4(uuid);
251		self
252	}
253
254	/// Extend with Uuid7 value
255	pub fn uuid7(mut self, uuid: &Uuid7) -> Self {
256		self.serializer.extend_uuid7(uuid);
257		self
258	}
259
260	/// Extend with Blob value
261	pub fn blob(mut self, blob: &Blob) -> Self {
262		self.serializer.extend_blob(blob);
263		self
264	}
265
266	/// Extend with arbitrary precision Int value
267	pub fn int(mut self, int: &Int) -> Self {
268		self.serializer.extend_int(int);
269		self
270	}
271
272	/// Extend with arbitrary precision Uint value
273	pub fn uint(mut self, uint: &Uint) -> Self {
274		self.serializer.extend_uint(uint);
275		self
276	}
277
278	/// Extend with Decimal value
279	pub fn decimal(mut self, decimal: &Decimal) -> Self {
280		self.serializer.extend_decimal(decimal);
281		self
282	}
283
284	/// Extend with a Value based on its type
285	pub fn value(mut self, value: &Value) -> Self {
286		self.serializer.extend_value(value);
287		self
288	}
289}
290
291impl Default for EncodedKeyBuilder {
292	fn default() -> Self {
293		Self::new()
294	}
295}
296
297/// Trait for types that can be converted into an EncodedKey.
298/// Provides convenient conversions from common types to EncodedKey using proper order-preserving encoding.
299pub trait IntoEncodedKey {
300	fn into_encoded_key(self) -> EncodedKey;
301}
302
303// Direct passthrough for EncodedKey
304impl IntoEncodedKey for EncodedKey {
305	fn into_encoded_key(self) -> EncodedKey {
306		self
307	}
308}
309
310// String types - using extend_str for proper encoding
311impl IntoEncodedKey for &str {
312	fn into_encoded_key(self) -> EncodedKey {
313		let mut serializer = KeySerializer::new();
314		serializer.extend_str(self);
315		serializer.to_encoded_key()
316	}
317}
318
319impl IntoEncodedKey for String {
320	fn into_encoded_key(self) -> EncodedKey {
321		let mut serializer = KeySerializer::new();
322		serializer.extend_str(&self);
323		serializer.to_encoded_key()
324	}
325}
326
327// Byte arrays - using extend_bytes for escaped encoding
328impl IntoEncodedKey for Vec<u8> {
329	fn into_encoded_key(self) -> EncodedKey {
330		let mut serializer = KeySerializer::new();
331		serializer.extend_bytes(&self);
332		serializer.to_encoded_key()
333	}
334}
335
336impl IntoEncodedKey for &[u8] {
337	fn into_encoded_key(self) -> EncodedKey {
338		let mut serializer = KeySerializer::new();
339		serializer.extend_bytes(self);
340		serializer.to_encoded_key()
341	}
342}
343
344// Numeric types - using proper encoding for order preservation
345impl IntoEncodedKey for u64 {
346	fn into_encoded_key(self) -> EncodedKey {
347		let mut serializer = KeySerializer::with_capacity(8);
348		serializer.extend_u64(self);
349		serializer.to_encoded_key()
350	}
351}
352
353impl IntoEncodedKey for i64 {
354	fn into_encoded_key(self) -> EncodedKey {
355		let mut serializer = KeySerializer::with_capacity(8);
356		serializer.extend_i64(self);
357		serializer.to_encoded_key()
358	}
359}
360
361impl IntoEncodedKey for u32 {
362	fn into_encoded_key(self) -> EncodedKey {
363		let mut serializer = KeySerializer::with_capacity(4);
364		serializer.extend_u32(self);
365		serializer.to_encoded_key()
366	}
367}
368
369impl IntoEncodedKey for i32 {
370	fn into_encoded_key(self) -> EncodedKey {
371		let mut serializer = KeySerializer::with_capacity(4);
372		serializer.extend_i32(self);
373		serializer.to_encoded_key()
374	}
375}
376
377impl IntoEncodedKey for u16 {
378	fn into_encoded_key(self) -> EncodedKey {
379		let mut serializer = KeySerializer::with_capacity(2);
380		serializer.extend_u16(self);
381		serializer.to_encoded_key()
382	}
383}
384
385impl IntoEncodedKey for i16 {
386	fn into_encoded_key(self) -> EncodedKey {
387		let mut serializer = KeySerializer::with_capacity(2);
388		serializer.extend_i16(self);
389		serializer.to_encoded_key()
390	}
391}
392
393impl IntoEncodedKey for u8 {
394	fn into_encoded_key(self) -> EncodedKey {
395		let mut serializer = KeySerializer::with_capacity(1);
396		serializer.extend_u8(self);
397		serializer.to_encoded_key()
398	}
399}
400
401impl IntoEncodedKey for i8 {
402	fn into_encoded_key(self) -> EncodedKey {
403		let mut serializer = KeySerializer::with_capacity(1);
404		serializer.extend_i8(self);
405		serializer.to_encoded_key()
406	}
407}
408
409#[derive(Clone, Debug)]
410pub struct EncodedKeyRange {
411	pub start: Bound<EncodedKey>,
412	pub end: Bound<EncodedKey>,
413}
414
415impl EncodedKeyRange {
416	pub fn new(start: Bound<EncodedKey>, end: Bound<EncodedKey>) -> Self {
417		Self {
418			start,
419			end,
420		}
421	}
422
423	/// Generates a key range for a key prefix, used e.g. for prefix scans.
424	///
425	/// The exclusive end bound is generated by adding 1 to the value of the
426	/// last byte. If the last byte(s) is 0xff (so adding 1 would
427	/// saturation), we instead find the latest non-0xff byte, increment
428	/// that, and truncate the rest. If all bytes are 0xff, we scan to the
429	/// end of the range, since there can't be other prefixes after it.
430	pub fn prefix(prefix: &[u8]) -> Self {
431		let start = Bound::Included(EncodedKey::new(prefix));
432		let end = match prefix.iter().rposition(|&b| b != 0xff) {
433			Some(i) => Bound::Excluded(EncodedKey::new(
434				prefix.iter()
435					.take(i)
436					.copied()
437					.chain(std::iter::once(prefix[i] + 1))
438					.collect::<Vec<_>>(),
439			)),
440			None => Bound::Unbounded,
441		};
442		Self {
443			start,
444			end,
445		}
446	}
447
448	pub fn with_prefix(&self, prefix: EncodedKey) -> Self {
449		let start = match self.start_bound() {
450			Included(key) => {
451				let mut prefixed = Vec::with_capacity(prefix.len() + key.len());
452				prefixed.extend_from_slice(prefix.as_ref());
453				prefixed.extend_from_slice(key.as_ref());
454				Included(EncodedKey::new(prefixed))
455			}
456			Excluded(key) => {
457				let mut prefixed = Vec::with_capacity(prefix.len() + key.len());
458				prefixed.extend_from_slice(prefix.as_ref());
459				prefixed.extend_from_slice(key.as_ref());
460				Excluded(EncodedKey::new(prefixed))
461			}
462			Unbounded => Included(prefix.clone()),
463		};
464
465		let end = match self.end_bound() {
466			Included(key) => {
467				let mut prefixed = Vec::with_capacity(prefix.len() + key.len());
468				prefixed.extend_from_slice(prefix.as_ref());
469				prefixed.extend_from_slice(key.as_ref());
470				Included(EncodedKey::new(prefixed))
471			}
472			Excluded(key) => {
473				let mut prefixed = Vec::with_capacity(prefix.len() + key.len());
474				prefixed.extend_from_slice(prefix.as_ref());
475				prefixed.extend_from_slice(key.as_ref());
476				Excluded(EncodedKey::new(prefixed))
477			}
478			Unbounded => match prefix.as_ref().iter().rposition(|&b| b != 0xff) {
479				Some(i) => {
480					let mut next_prefix = prefix.as_ref()[..=i].to_vec();
481					next_prefix[i] += 1;
482					Excluded(EncodedKey::new(next_prefix))
483				}
484				None => Unbounded,
485			},
486		};
487
488		EncodedKeyRange::new(start, end)
489	}
490
491	/// Constructs a key range from an optional inclusive start key to an
492	/// optional inclusive end key.
493	///
494	/// - `start`: If provided, marks the inclusive lower bound of the range. If `None`, the range is unbounded
495	///   below.
496	/// - `end`: If provided, marks the inclusive upper bound of the range. If `None`, the range is unbounded above.
497	///
498	/// This function does not modify the input keys and assumes they are
499	/// already exact keys (not prefixes). If you need to scan all keys
500	/// with a given prefix, use [`EncodedKeyRange::prefix`] instead.
501	///
502	/// Useful for scanning between two explicit keys in a sorted key-value
503	/// store.
504	pub fn start_end(start: Option<EncodedKey>, end: Option<EncodedKey>) -> Self {
505		let start = match start {
506			Some(s) => Bound::Included(s),
507			None => Bound::Unbounded,
508		};
509
510		let end = match end {
511			Some(e) => Bound::Included(e),
512			None => Bound::Unbounded,
513		};
514
515		Self {
516			start,
517			end,
518		}
519	}
520
521	/// Constructs a key range that fragments the entire keyspace.
522	///
523	/// This range has no lower or upper bounds, making it suitable for full
524	/// scans over all keys in a sorted key-value store.
525	///
526	/// Equivalent to: `..` (in Rust range syntax)
527	pub fn all() -> Self {
528		Self {
529			start: Bound::Unbounded,
530			end: Bound::Unbounded,
531		}
532	}
533
534	/// Parses a human-readable range string into a `KeyRange`.
535	///
536	/// The expected format is `<start>..[=]<end>`, where:
537	/// - `<start>` is the inclusive lower bound (optional),
538	/// - `..` separates the bounds,
539	/// - `=` after `..` makes the upper bound inclusive,
540	/// - `<end>` is the upper bound (optional).
541	///
542	/// Examples:
543	/// - `"a..z"`       => start = Included("a"), end = Excluded("z")
544	/// - `"a..=z"`      => start = Included("a"), end = Included("z")
545	/// - `"..z"`        => start = Unbounded,     end = Excluded("z")
546	/// - `"a.."`        => start = Included("a"), end = Unbounded
547	///
548	/// If parsing fails, it defaults to a degenerate range from `0xff` to
549	/// `0xff` (empty).
550	pub fn parse(str: &str) -> Self {
551		let (mut start, mut end) = (Bound::<EncodedKey>::Unbounded, Bound::<EncodedKey>::Unbounded);
552
553		// Find the ".." separator
554		if let Some(dot_pos) = str.find("..") {
555			let start_part = &str[..dot_pos];
556			let end_part = &str[dot_pos + 2..];
557
558			// Parse start bound
559			if !start_part.is_empty() {
560				start = Bound::Included(EncodedKey(decode_binary(start_part)));
561			}
562
563			// Parse end bound - check for inclusive marker "="
564			if let Some(end_str) = end_part.strip_prefix('=') {
565				// Inclusive end: "..="
566				if !end_str.is_empty() {
567					end = Bound::Included(EncodedKey(decode_binary(end_str)));
568				}
569			} else {
570				// Exclusive end: ".."
571				if !end_part.is_empty() {
572					end = Bound::Excluded(EncodedKey(decode_binary(end_part)));
573				}
574			}
575
576			Self {
577				start,
578				end,
579			}
580		} else {
581			// Invalid format - return degenerate range
582			Self {
583				start: Bound::Included(EncodedKey::new([0xff])),
584				end: Bound::Excluded(EncodedKey::new([0xff])),
585			}
586		}
587	}
588}
589
590impl RangeBounds<EncodedKey> for EncodedKeyRange {
591	fn start_bound(&self) -> Bound<&EncodedKey> {
592		self.start.as_ref()
593	}
594
595	fn end_bound(&self) -> Bound<&EncodedKey> {
596		self.end.as_ref()
597	}
598}
599
600#[cfg(test)]
601mod tests {
602	use std::collections::Bound;
603
604	use super::EncodedKey;
605
606	macro_rules! as_key {
607		($key:expr) => {{ EncodedKey::new(keycode::serialize(&$key)) }};
608	}
609
610	mod prefix {
611		use std::ops::Bound;
612
613		use crate::value::encoded::key::{
614			EncodedKeyRange,
615			tests::{excluded, included},
616		};
617
618		#[test]
619		fn test_simple() {
620			let range = EncodedKeyRange::prefix(&[0x12, 0x34]);
621			assert_eq!(range.start, included(&[0x12, 0x34]));
622			assert_eq!(range.end, excluded(&[0x12, 0x35]));
623		}
624
625		#[test]
626		fn test_with_trailing_ff() {
627			let range = EncodedKeyRange::prefix(&[0x12, 0xff]);
628			assert_eq!(range.start, included(&[0x12, 0xff]));
629			assert_eq!(range.end, excluded(&[0x13]));
630		}
631
632		#[test]
633		fn test_with_multiple_trailing_ff() {
634			let range = EncodedKeyRange::prefix(&[0x12, 0xff, 0xff]);
635			assert_eq!(range.start, included(&[0x12, 0xff, 0xff]));
636			assert_eq!(range.end, excluded(&[0x13]));
637		}
638
639		#[test]
640		fn test_all_ff() {
641			let range = EncodedKeyRange::prefix(&[0xff, 0xff]);
642			assert_eq!(range.start, included(&[0xff, 0xff]));
643			assert_eq!(range.end, Bound::Unbounded);
644		}
645
646		#[test]
647		fn test_empty() {
648			let range = EncodedKeyRange::prefix(&[]);
649			assert_eq!(range.start, included(&[]));
650			assert_eq!(range.end, Bound::Unbounded);
651		}
652
653		#[test]
654		fn test_mid_increment() {
655			let range = EncodedKeyRange::prefix(&[0x12, 0x00, 0xff]);
656			assert_eq!(range.start, included(&[0x12, 0x00, 0xff]));
657			assert_eq!(range.end, excluded(&[0x12, 0x01]));
658		}
659	}
660
661	mod start_end {
662		use std::ops::Bound;
663
664		use crate::{
665			EncodedKey,
666			util::encoding::keycode,
667			value::encoded::key::{EncodedKeyRange, tests::included},
668		};
669
670		#[test]
671		fn test_start_and_end() {
672			let range = EncodedKeyRange::start_end(Some(as_key!(1)), Some(as_key!(2)));
673			assert_eq!(range.start, included(&as_key!(1)));
674			assert_eq!(range.end, included(&as_key!(2)));
675		}
676
677		#[test]
678		fn test_start_only() {
679			let range = EncodedKeyRange::start_end(Some(as_key!(1)), None);
680			assert_eq!(range.start, included(&as_key!(1)));
681			assert_eq!(range.end, Bound::Unbounded);
682		}
683
684		#[test]
685		fn test_end_only() {
686			let range = EncodedKeyRange::start_end(None, Some(as_key!(2)));
687			assert_eq!(range.start, Bound::Unbounded);
688			assert_eq!(range.end, included(&as_key!(2)));
689		}
690
691		#[test]
692		fn test_unbounded_range() {
693			let range = EncodedKeyRange::start_end(None, None);
694			assert_eq!(range.start, Bound::Unbounded);
695			assert_eq!(range.end, Bound::Unbounded);
696		}
697
698		#[test]
699		fn test_full_byte_range() {
700			let range = EncodedKeyRange::start_end(Some(as_key!(0x00)), Some(as_key!(0xff)));
701			assert_eq!(range.start, included(&as_key!(0x00)));
702			assert_eq!(range.end, included(&as_key!(0xff)));
703		}
704
705		#[test]
706		fn test_identical_bounds() {
707			let range = EncodedKeyRange::start_end(Some(as_key!(0x42)), Some(as_key!(0x42)));
708			assert_eq!(range.start, included(&as_key!(0x42)));
709			assert_eq!(range.end, included(&as_key!(0x42)));
710		}
711	}
712
713	mod all {
714		use std::ops::Bound;
715
716		use crate::value::encoded::key::EncodedKeyRange;
717
718		#[test]
719		fn test_is_unbounded() {
720			let range = EncodedKeyRange::all();
721			assert_eq!(range.start, Bound::Unbounded);
722			assert_eq!(range.end, Bound::Unbounded);
723		}
724	}
725
726	mod parse {
727		use std::ops::Bound;
728
729		use crate::value::encoded::key::{
730			EncodedKey, EncodedKeyRange,
731			tests::{excluded, included},
732		};
733
734		#[test]
735		fn test_full_range() {
736			let r = EncodedKeyRange::parse("a..z");
737			assert_eq!(r.start, included(b"a"));
738			assert_eq!(r.end, excluded(b"z"));
739		}
740
741		#[test]
742		fn test_inclusive_end() {
743			let r = EncodedKeyRange::parse("a..=z");
744			assert_eq!(r.start, included(b"a"));
745			assert_eq!(r.end, included(b"z"));
746		}
747
748		#[test]
749		fn test_unbounded_start() {
750			let r = EncodedKeyRange::parse("..z");
751			assert_eq!(r.start, Bound::Unbounded);
752			assert_eq!(r.end, excluded(b"z"));
753		}
754
755		#[test]
756		fn test_unbounded_end() {
757			let r = EncodedKeyRange::parse("a..");
758			assert_eq!(r.start, included(b"a"));
759			assert_eq!(r.end, Bound::Unbounded);
760		}
761
762		#[test]
763		fn test_inclusive_only() {
764			let r = EncodedKeyRange::parse("..=z");
765			assert_eq!(r.start, Bound::Unbounded);
766			assert_eq!(r.end, included(b"z"));
767		}
768
769		#[test]
770		fn test_invalid_string_returns_degenerate_range() {
771			let r = EncodedKeyRange::parse("not a range");
772			let expected = EncodedKey::new([0xff]);
773			assert_eq!(r.start, Bound::Included(expected.clone()));
774			assert_eq!(r.end, Bound::Excluded(expected));
775		}
776
777		#[test]
778		fn test_empty_string_returns_degenerate_range() {
779			let r = EncodedKeyRange::parse("");
780			let expected = EncodedKey::new([0xff]);
781			assert_eq!(r.start, Bound::Included(expected.clone()));
782			assert_eq!(r.end, Bound::Excluded(expected));
783		}
784
785		#[test]
786		fn test_binary_encoded_values() {
787			let r = EncodedKeyRange::parse("0101..=0aff");
788			// decode_binary("0101") = [0x01, 0x01]
789			assert_eq!(r.start, included(b"0101"));
790			// decode_binary("0aff") = [0x0a, 0xff]
791			assert_eq!(r.end, included(b"0aff"));
792		}
793	}
794
795	fn included(key: &[u8]) -> Bound<EncodedKey> {
796		Bound::Included(EncodedKey::new(key))
797	}
798
799	fn excluded(key: &[u8]) -> Bound<EncodedKey> {
800		Bound::Excluded(EncodedKey::new(key))
801	}
802}