reifydb_core/value/index/
range.rs1use std::collections::Bound;
5
6use super::EncodedIndexKey;
7use crate::value::encoded::{EncodedKey, EncodedKeyRange};
8
9#[derive(Clone, Debug)]
10pub struct EncodedIndexKeyRange {
11 pub start: Bound<EncodedIndexKey>,
12 pub end: Bound<EncodedIndexKey>,
13}
14
15impl EncodedIndexKeyRange {
16 pub fn new(start: Bound<EncodedIndexKey>, end: Bound<EncodedIndexKey>) -> Self {
17 Self {
18 start,
19 end,
20 }
21 }
22
23 pub fn start_end(start: Option<EncodedIndexKey>, end: Option<EncodedIndexKey>) -> Self {
31 let start = match start {
32 Some(s) => Bound::Included(s),
33 None => Bound::Unbounded,
34 };
35
36 let end = match end {
37 Some(e) => Bound::Excluded(e),
38 None => Bound::Unbounded,
39 };
40
41 Self {
42 start,
43 end,
44 }
45 }
46
47 pub fn start_end_inclusive(start: Option<EncodedIndexKey>, end: Option<EncodedIndexKey>) -> Self {
56 let start = match start {
57 Some(s) => Bound::Included(s),
58 None => Bound::Unbounded,
59 };
60
61 let end = match end {
62 Some(e) => Bound::Included(e),
63 None => Bound::Unbounded,
64 };
65
66 Self {
67 start,
68 end,
69 }
70 }
71
72 pub fn prefix(prefix: &[u8]) -> Self {
81 let start = Bound::Included(EncodedIndexKey::from_bytes(prefix));
82 let end = match prefix.iter().rposition(|&b| b != 0xff) {
83 Some(i) => Bound::Excluded(EncodedIndexKey::from_bytes(
84 &prefix.iter()
85 .take(i)
86 .copied()
87 .chain(std::iter::once(prefix[i] + 1))
88 .collect::<Vec<_>>(),
89 )),
90 None => Bound::Unbounded,
91 };
92 Self {
93 start,
94 end,
95 }
96 }
97
98 pub fn all() -> Self {
100 Self {
101 start: Bound::Unbounded,
102 end: Bound::Unbounded,
103 }
104 }
105
106 pub fn to_encoded_key_range(&self) -> EncodedKeyRange {
110 let start = match &self.start {
111 Bound::Included(key) => Bound::Included(EncodedKey::new(key.as_slice())),
112 Bound::Excluded(key) => Bound::Excluded(EncodedKey::new(key.as_slice())),
113 Bound::Unbounded => Bound::Unbounded,
114 };
115
116 let end = match &self.end {
117 Bound::Included(key) => Bound::Included(EncodedKey::new(key.as_slice())),
118 Bound::Excluded(key) => Bound::Excluded(EncodedKey::new(key.as_slice())),
119 Bound::Unbounded => Bound::Unbounded,
120 };
121
122 EncodedKeyRange::new(start, end)
123 }
124
125 pub fn from_prefix(key: &EncodedIndexKey) -> Self {
128 Self::prefix(key.as_slice())
129 }
130}
131
132impl From<EncodedIndexKeyRange> for EncodedKeyRange {
133 fn from(range: EncodedIndexKeyRange) -> Self {
134 range.to_encoded_key_range()
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use reifydb_type::Type;
141
142 use super::*;
143 use crate::{SortDirection, value::index::EncodedIndexLayout};
144
145 #[test]
146 fn test_start_end() {
147 let layout = EncodedIndexLayout::new(&[Type::Uint8], &[SortDirection::Asc]).unwrap();
148
149 let mut key1 = layout.allocate_key();
150 layout.set_u64(&mut key1, 0, 100u64);
151
152 let mut key2 = layout.allocate_key();
153 layout.set_u64(&mut key2, 0, 200u64);
154
155 let range = EncodedIndexKeyRange::start_end(Some(key1.clone()), Some(key2.clone()));
156
157 match &range.start {
158 Bound::Included(k) => {
159 assert_eq!(k.as_slice(), key1.as_slice())
160 }
161 _ => panic!("Expected Included start bound"),
162 }
163
164 match &range.end {
165 Bound::Excluded(k) => {
166 assert_eq!(k.as_slice(), key2.as_slice())
167 }
168 _ => panic!("Expected Excluded end bound"),
169 }
170 }
171
172 #[test]
173 fn test_start_end_inclusive() {
174 let layout = EncodedIndexLayout::new(&[Type::Uint8], &[SortDirection::Asc]).unwrap();
175
176 let mut key1 = layout.allocate_key();
177 layout.set_u64(&mut key1, 0, 100u64);
178
179 let mut key2 = layout.allocate_key();
180 layout.set_u64(&mut key2, 0, 200u64);
181
182 let range = EncodedIndexKeyRange::start_end_inclusive(Some(key1.clone()), Some(key2.clone()));
183
184 match &range.start {
185 Bound::Included(k) => {
186 assert_eq!(k.as_slice(), key1.as_slice())
187 }
188 _ => panic!("Expected Included start bound"),
189 }
190
191 match &range.end {
192 Bound::Included(k) => {
193 assert_eq!(k.as_slice(), key2.as_slice())
194 }
195 _ => panic!("Expected Included end bound"),
196 }
197 }
198
199 #[test]
200 fn test_unbounded() {
201 let range = EncodedIndexKeyRange::start_end(None, None);
202 assert!(matches!(range.start, Bound::Unbounded));
203 assert!(matches!(range.end, Bound::Unbounded));
204 }
205
206 #[test]
207 fn test_prefix() {
208 let prefix = &[0x12, 0x34];
209 let range = EncodedIndexKeyRange::prefix(prefix);
210
211 match &range.start {
212 Bound::Included(k) => assert_eq!(k.as_slice(), prefix),
213 _ => panic!("Expected Included start bound"),
214 }
215
216 match &range.end {
217 Bound::Excluded(k) => {
218 assert_eq!(k.as_slice(), &[0x12, 0x35])
219 }
220 _ => panic!("Expected Excluded end bound"),
221 }
222 }
223
224 #[test]
225 fn test_prefix_with_ff() {
226 let prefix = &[0x12, 0xff];
227 let range = EncodedIndexKeyRange::prefix(prefix);
228
229 match &range.start {
230 Bound::Included(k) => assert_eq!(k.as_slice(), prefix),
231 _ => panic!("Expected Included start bound"),
232 }
233
234 match &range.end {
235 Bound::Excluded(k) => assert_eq!(k.as_slice(), &[0x13]),
236 _ => panic!("Expected Excluded end bound"),
237 }
238 }
239
240 #[test]
241 fn test_prefix_all_ff() {
242 let prefix = &[0xff, 0xff];
243 let range = EncodedIndexKeyRange::prefix(prefix);
244
245 match &range.start {
246 Bound::Included(k) => assert_eq!(k.as_slice(), prefix),
247 _ => panic!("Expected Included start bound"),
248 }
249
250 assert!(matches!(range.end, Bound::Unbounded));
251 }
252
253 #[test]
254 fn test_to_encoded_key_range() {
255 let layout = EncodedIndexLayout::new(&[Type::Uint8], &[SortDirection::Asc]).unwrap();
256
257 let mut key = layout.allocate_key();
258 layout.set_u64(&mut key, 0, 100u64);
259
260 let index_range = EncodedIndexKeyRange::start_end(Some(key.clone()), None);
261 let key_range = index_range.to_encoded_key_range();
262
263 match &key_range.start {
264 Bound::Included(k) => {
265 assert_eq!(k.as_slice(), key.as_slice())
266 }
267 _ => panic!("Expected Included start bound"),
268 }
269
270 assert!(matches!(key_range.end, Bound::Unbounded));
271 }
272
273 #[test]
274 fn test_all() {
275 let range = EncodedIndexKeyRange::all();
276 assert!(matches!(range.start, Bound::Unbounded));
277 assert!(matches!(range.end, Bound::Unbounded));
278 }
279}