reifydb_core/value/index/
range.rs1use std::{collections::Bound, iter};
5
6use reifydb_codec::key::encoded::{EncodedKey, EncodedKeyRange};
7
8use crate::value::index::encoded::EncodedIndexKey;
9
10#[derive(Clone, Debug)]
11pub struct EncodedIndexKeyRange {
12 pub start: Bound<EncodedIndexKey>,
13 pub end: Bound<EncodedIndexKey>,
14}
15
16impl EncodedIndexKeyRange {
17 pub fn new(start: Bound<EncodedIndexKey>, end: Bound<EncodedIndexKey>) -> Self {
18 Self {
19 start,
20 end,
21 }
22 }
23
24 pub fn start_end(start: Option<EncodedIndexKey>, end: Option<EncodedIndexKey>) -> Self {
25 let start = match start {
26 Some(s) => Bound::Included(s),
27 None => Bound::Unbounded,
28 };
29
30 let end = match end {
31 Some(e) => Bound::Excluded(e),
32 None => Bound::Unbounded,
33 };
34
35 Self {
36 start,
37 end,
38 }
39 }
40
41 pub fn prefix(prefix: &[u8]) -> Self {
42 let start = Bound::Included(EncodedIndexKey::from_bytes(prefix));
43 let end = match prefix.iter().rposition(|&b| b != 0xff) {
44 Some(i) => Bound::Excluded(EncodedIndexKey::from_bytes(
45 &prefix.iter().take(i).copied().chain(iter::once(prefix[i] + 1)).collect::<Vec<_>>(),
46 )),
47 None => Bound::Unbounded,
48 };
49 Self {
50 start,
51 end,
52 }
53 }
54
55 pub fn all() -> Self {
56 Self {
57 start: Bound::Unbounded,
58 end: Bound::Unbounded,
59 }
60 }
61
62 pub fn to_encoded_key_range(&self) -> EncodedKeyRange {
63 let start = match &self.start {
64 Bound::Included(key) => Bound::Included(EncodedKey::new(key.as_slice())),
65 Bound::Excluded(key) => Bound::Excluded(EncodedKey::new(key.as_slice())),
66 Bound::Unbounded => Bound::Unbounded,
67 };
68
69 let end = match &self.end {
70 Bound::Included(key) => Bound::Included(EncodedKey::new(key.as_slice())),
71 Bound::Excluded(key) => Bound::Excluded(EncodedKey::new(key.as_slice())),
72 Bound::Unbounded => Bound::Unbounded,
73 };
74
75 EncodedKeyRange::new(start, end)
76 }
77}
78
79impl From<EncodedIndexKeyRange> for EncodedKeyRange {
80 fn from(range: EncodedIndexKeyRange) -> Self {
81 range.to_encoded_key_range()
82 }
83}
84
85#[cfg(test)]
86pub mod tests {
87 use reifydb_value::value::value_type::ValueType;
88
89 use super::*;
90 use crate::{sort::SortDirection, value::index::shape::IndexShape};
91
92 #[test]
93 fn test_start_end() {
94 let layout = IndexShape::new(&[ValueType::Uint8], &[SortDirection::Asc]).unwrap();
95
96 let mut key1 = layout.allocate_key();
97 layout.set_u64(&mut key1, 0, 100u64);
98
99 let mut key2 = layout.allocate_key();
100 layout.set_u64(&mut key2, 0, 200u64);
101
102 let range = EncodedIndexKeyRange::start_end(Some(key1.clone()), Some(key2.clone()));
103
104 match &range.start {
105 Bound::Included(k) => {
106 assert_eq!(k.as_slice(), key1.as_slice())
107 }
108 _ => panic!("Expected Included start bound"),
109 }
110
111 match &range.end {
112 Bound::Excluded(k) => {
113 assert_eq!(k.as_slice(), key2.as_slice())
114 }
115 _ => panic!("Expected Excluded end bound"),
116 }
117 }
118
119 #[test]
120 fn test_unbounded() {
121 let range = EncodedIndexKeyRange::start_end(None, None);
122 assert!(matches!(range.start, Bound::Unbounded));
123 assert!(matches!(range.end, Bound::Unbounded));
124 }
125
126 #[test]
127 fn test_prefix() {
128 let prefix = &[0x12, 0x34];
129 let range = EncodedIndexKeyRange::prefix(prefix);
130
131 match &range.start {
132 Bound::Included(k) => assert_eq!(k.as_slice(), prefix),
133 _ => panic!("Expected Included start bound"),
134 }
135
136 match &range.end {
137 Bound::Excluded(k) => {
138 assert_eq!(k.as_slice(), &[0x12, 0x35])
139 }
140 _ => panic!("Expected Excluded end bound"),
141 }
142 }
143
144 #[test]
145 fn test_prefix_with_ff() {
146 let prefix = &[0x12, 0xff];
147 let range = EncodedIndexKeyRange::prefix(prefix);
148
149 match &range.start {
150 Bound::Included(k) => assert_eq!(k.as_slice(), prefix),
151 _ => panic!("Expected Included start bound"),
152 }
153
154 match &range.end {
155 Bound::Excluded(k) => assert_eq!(k.as_slice(), &[0x13]),
156 _ => panic!("Expected Excluded end bound"),
157 }
158 }
159
160 #[test]
161 fn test_prefix_all_ff() {
162 let prefix = &[0xff, 0xff];
163 let range = EncodedIndexKeyRange::prefix(prefix);
164
165 match &range.start {
166 Bound::Included(k) => assert_eq!(k.as_slice(), prefix),
167 _ => panic!("Expected Included start bound"),
168 }
169
170 assert!(matches!(range.end, Bound::Unbounded));
171 }
172
173 #[test]
174 fn test_to_encoded_key_range() {
175 let layout = IndexShape::new(&[ValueType::Uint8], &[SortDirection::Asc]).unwrap();
176
177 let mut key = layout.allocate_key();
178 layout.set_u64(&mut key, 0, 100u64);
179
180 let index_range = EncodedIndexKeyRange::start_end(Some(key.clone()), None);
181 let key_range = index_range.to_encoded_key_range();
182
183 match &key_range.start {
184 Bound::Included(k) => {
185 assert_eq!(k.as_slice(), key.as_slice())
186 }
187 _ => panic!("Expected Included start bound"),
188 }
189
190 assert!(matches!(key_range.end, Bound::Unbounded));
191 }
192
193 #[test]
194 fn test_all() {
195 let range = EncodedIndexKeyRange::all();
196 assert!(matches!(range.start, Bound::Unbounded));
197 assert!(matches!(range.end, Bound::Unbounded));
198 }
199}