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