1use crate::buckets::key::{BucketedKey, KeyBuilder};
6use crate::buckets::BucketError;
7use redb::{MultimapRange, MultimapValue, ReadOnlyMultimapTable, ReadOnlyTable};
8
9pub struct BucketRangeIterator<V>
16where
17 V: redb::Value + 'static,
18 for<'b> V: From<V::SelfType<'b>>,
19{
20 range: redb::Range<'static, BucketedKey<u64>, V>,
21 base_key: u64,
22 start_bucket: u64,
23 end_bucket: u64,
24 finished: bool,
25}
26
27impl<V> BucketRangeIterator<V>
28where
29 V: redb::Value + 'static,
30 for<'b> V: From<V::SelfType<'b>>,
31{
32 pub fn new(
34 table: &ReadOnlyTable<BucketedKey<u64>, V>,
35 key_builder: &KeyBuilder,
36 base_key: u64,
37 start_sequence: u64,
38 end_sequence: u64,
39 ) -> Result<Self, BucketError> {
40 if start_sequence > end_sequence {
41 return Err(BucketError::InvalidRange {
42 start: start_sequence,
43 end: end_sequence,
44 });
45 }
46
47 let bucket_size = key_builder.bucket_size();
48 let start_bucket = start_sequence / bucket_size;
49 let end_bucket = end_sequence / bucket_size;
50 let start_key = BucketedKey::new(base_key, start_bucket);
51 let end_key = BucketedKey::new(base_key, end_bucket);
52 let range = table.range(start_key..=end_key).map_err(|err| {
53 BucketError::IterationError(format!("Failed to create range iterator: {}", err))
54 })?;
55
56 Ok(Self {
57 range,
58 base_key,
59 start_bucket,
60 end_bucket,
61 finished: false,
62 })
63 }
64
65 pub fn bucket_range(&self) -> (u64, u64) {
67 (self.start_bucket, self.end_bucket)
68 }
69}
70
71impl<V> Iterator for BucketRangeIterator<V>
72where
73 V: redb::Value + 'static,
74 for<'b> V: From<V::SelfType<'b>>,
75{
76 type Item = Result<V, BucketError>;
77
78 fn next(&mut self) -> Option<Self::Item> {
79 if self.finished {
80 return None;
81 }
82
83 loop {
84 match self.range.next() {
85 Some(Ok((key_guard, value_guard))) => {
86 let key = key_guard.value();
87 if key.base_key == self.base_key {
88 return Some(Ok(V::from(value_guard.value())));
89 }
90 }
91 Some(Err(err)) => {
92 self.finished = true;
93 return Some(Err(BucketError::IterationError(format!(
94 "Database error during iteration: {}",
95 err
96 ))));
97 }
98 None => {
99 self.finished = true;
100 return None;
101 }
102 }
103 }
104 }
105}
106
107impl<V> DoubleEndedIterator for BucketRangeIterator<V>
108where
109 V: redb::Value + 'static,
110 for<'b> V: From<V::SelfType<'b>>,
111{
112 fn next_back(&mut self) -> Option<Self::Item> {
113 if self.finished {
114 return None;
115 }
116
117 loop {
118 match self.range.next_back() {
119 Some(Ok((key_guard, value_guard))) => {
120 let key = key_guard.value();
121 if key.base_key == self.base_key {
122 return Some(Ok(V::from(value_guard.value())));
123 }
124 }
125 Some(Err(err)) => {
126 self.finished = true;
127 return Some(Err(BucketError::IterationError(format!(
128 "Database error during iteration: {}",
129 err
130 ))));
131 }
132 None => {
133 self.finished = true;
134 return None;
135 }
136 }
137 }
138 }
139}
140
141pub struct BucketRangeMultimapIterator<V>
177where
178 V: redb::Key + 'static,
179 for<'b> V: From<V::SelfType<'b>>,
180{
181 range: MultimapRange<'static, BucketedKey<u64>, V>,
182 base_key: u64,
183 start_bucket: u64,
184 end_bucket: u64,
185 finished: bool,
186 front_values: Option<MultimapValue<'static, V>>,
187 back_values: Option<MultimapValue<'static, V>>,
188}
189
190impl<V> BucketRangeMultimapIterator<V>
191where
192 V: redb::Key + 'static,
193 for<'b> V: From<V::SelfType<'b>>,
194{
195 pub fn new(
197 table: &ReadOnlyMultimapTable<BucketedKey<u64>, V>,
198 key_builder: &KeyBuilder,
199 base_key: u64,
200 start_sequence: u64,
201 end_sequence: u64,
202 ) -> Result<Self, BucketError> {
203 if start_sequence > end_sequence {
204 return Err(BucketError::InvalidRange {
205 start: start_sequence,
206 end: end_sequence,
207 });
208 }
209
210 let bucket_size = key_builder.bucket_size();
211 let start_bucket = start_sequence / bucket_size;
212 let end_bucket = end_sequence / bucket_size;
213 let start_key = BucketedKey::new(base_key, start_bucket);
214 let end_key = BucketedKey::new(base_key, end_bucket);
215 let range = table.range(start_key..=end_key).map_err(|err| {
216 BucketError::IterationError(format!("Failed to create range iterator: {}", err))
217 })?;
218
219 Ok(Self {
220 range,
221 base_key,
222 start_bucket,
223 end_bucket,
224 finished: false,
225 front_values: None,
226 back_values: None,
227 })
228 }
229
230 pub fn bucket_range(&self) -> (u64, u64) {
232 (self.start_bucket, self.end_bucket)
233 }
234}
235
236impl<V> Iterator for BucketRangeMultimapIterator<V>
237where
238 V: redb::Key + 'static,
239 for<'b> V: From<V::SelfType<'b>>,
240{
241 type Item = Result<V, BucketError>;
242
243 fn next(&mut self) -> Option<Self::Item> {
244 if self.finished {
245 return None;
246 }
247
248 loop {
249 if let Some(values) = self.front_values.as_mut() {
250 match values.next() {
251 Some(Ok(value_guard)) => {
252 return Some(Ok(V::from(value_guard.value())));
253 }
254 Some(Err(err)) => {
255 self.finished = true;
256 return Some(Err(BucketError::IterationError(format!(
257 "Database error during iteration: {}",
258 err
259 ))));
260 }
261 None => {
262 self.front_values = None;
263 }
264 }
265 }
266
267 match self.range.next() {
268 Some(Ok((key_guard, values))) => {
269 let key = key_guard.value();
270 if key.base_key == self.base_key {
271 self.front_values = Some(values);
272 }
273 }
274 Some(Err(err)) => {
275 self.finished = true;
276 return Some(Err(BucketError::IterationError(format!(
277 "Database error during iteration: {}",
278 err
279 ))));
280 }
281 None => {
282 if let Some(values) = self.back_values.as_mut() {
283 match values.next() {
284 Some(Ok(value_guard)) => {
285 return Some(Ok(V::from(value_guard.value())));
286 }
287 Some(Err(err)) => {
288 self.finished = true;
289 return Some(Err(BucketError::IterationError(format!(
290 "Database error during iteration: {}",
291 err
292 ))));
293 }
294 None => {
295 self.back_values = None;
296 }
297 }
298 }
299
300 if self.front_values.is_none() && self.back_values.is_none() {
301 self.finished = true;
302 return None;
303 }
304 }
305 }
306 }
307 }
308}
309
310impl<V> DoubleEndedIterator for BucketRangeMultimapIterator<V>
311where
312 V: redb::Key + 'static,
313 for<'b> V: From<V::SelfType<'b>>,
314{
315 fn next_back(&mut self) -> Option<Self::Item> {
316 if self.finished {
317 return None;
318 }
319
320 loop {
321 if let Some(values) = self.back_values.as_mut() {
322 match values.next_back() {
323 Some(Ok(value_guard)) => {
324 return Some(Ok(V::from(value_guard.value())));
325 }
326 Some(Err(err)) => {
327 self.finished = true;
328 return Some(Err(BucketError::IterationError(format!(
329 "Database error during iteration: {}",
330 err
331 ))));
332 }
333 None => {
334 self.back_values = None;
335 }
336 }
337 }
338
339 match self.range.next_back() {
340 Some(Ok((key_guard, values))) => {
341 let key = key_guard.value();
342 if key.base_key == self.base_key {
343 self.back_values = Some(values);
344 }
345 }
346 Some(Err(err)) => {
347 self.finished = true;
348 return Some(Err(BucketError::IterationError(format!(
349 "Database error during iteration: {}",
350 err
351 ))));
352 }
353 None => {
354 if let Some(values) = self.front_values.as_mut() {
355 match values.next_back() {
356 Some(Ok(value_guard)) => {
357 return Some(Ok(V::from(value_guard.value())));
358 }
359 Some(Err(err)) => {
360 self.finished = true;
361 return Some(Err(BucketError::IterationError(format!(
362 "Database error during iteration: {}",
363 err
364 ))));
365 }
366 None => {
367 self.front_values = None;
368 }
369 }
370 }
371
372 if self.front_values.is_none() && self.back_values.is_none() {
373 self.finished = true;
374 return None;
375 }
376 }
377 }
378 }
379 }
380}
381
382pub trait BucketIterExt<V>
384where
385 V: redb::Value + 'static,
386 for<'b> V: From<V::SelfType<'b>>,
387{
388 fn bucket_range(
389 &self,
390 key_builder: &KeyBuilder,
391 base_key: u64,
392 start_sequence: u64,
393 end_sequence: u64,
394 ) -> Result<BucketRangeIterator<V>, BucketError>;
395}
396
397impl<V> BucketIterExt<V> for ReadOnlyTable<BucketedKey<u64>, V>
398where
399 V: redb::Value + 'static,
400 for<'b> V: From<V::SelfType<'b>>,
401{
402 fn bucket_range(
403 &self,
404 key_builder: &KeyBuilder,
405 base_key: u64,
406 start_sequence: u64,
407 end_sequence: u64,
408 ) -> Result<BucketRangeIterator<V>, BucketError> {
409 BucketRangeIterator::new(self, key_builder, base_key, start_sequence, end_sequence)
410 }
411}
412
413pub trait BucketMultimapIterExt<V>
418where
419 V: redb::Key + 'static,
420 for<'b> V: From<V::SelfType<'b>>,
421{
422 fn bucket_range(
423 &self,
424 key_builder: &KeyBuilder,
425 base_key: u64,
426 start_sequence: u64,
427 end_sequence: u64,
428 ) -> Result<BucketRangeMultimapIterator<V>, BucketError>;
429}
430
431impl<V> BucketMultimapIterExt<V> for ReadOnlyMultimapTable<BucketedKey<u64>, V>
432where
433 V: redb::Key + 'static,
434 for<'b> V: From<V::SelfType<'b>>,
435{
436 fn bucket_range(
437 &self,
438 key_builder: &KeyBuilder,
439 base_key: u64,
440 start_sequence: u64,
441 end_sequence: u64,
442 ) -> Result<BucketRangeMultimapIterator<V>, BucketError> {
443 BucketRangeMultimapIterator::new(self, key_builder, base_key, start_sequence, end_sequence)
444 }
445}
446
447#[cfg(test)]
448mod tests {
449 use super::*;
450 use redb::{Database, MultimapTableDefinition, ReadableDatabase, TableDefinition};
451 use tempfile::NamedTempFile;
452
453 const TEST_TABLE: TableDefinition<'static, BucketedKey<u64>, String> =
454 TableDefinition::new("test_table");
455 const TEST_MULTIMAP: MultimapTableDefinition<'static, BucketedKey<u64>, u64> =
456 MultimapTableDefinition::new("test_multimap");
457
458 #[test]
459 fn test_basic_functionality() -> Result<(), Box<dyn std::error::Error>> {
460 let temp_file = NamedTempFile::new()?;
461 let db = Database::create(temp_file.path())?;
462 let key_builder = KeyBuilder::new(100)?;
463
464 {
466 let write_txn = db.begin_write()?;
467 {
468 let mut table = write_txn.open_table(TEST_TABLE)?;
469
470 table.insert(key_builder.bucketed_key(123u64, 50), "value_50".to_string())?;
472 table.insert(
473 key_builder.bucketed_key(123u64, 150),
474 "value_150".to_string(),
475 )?;
476 table.insert(
477 key_builder.bucketed_key(123u64, 250),
478 "value_250".to_string(),
479 )?;
480
481 table.insert(key_builder.bucketed_key(456u64, 50), "other_50".to_string())?;
483 table.insert(
484 key_builder.bucketed_key(456u64, 150),
485 "other_150".to_string(),
486 )?;
487 }
488 write_txn.commit()?;
489 }
490
491 {
493 let read_txn = db.begin_read()?;
494 let table = read_txn.open_table(TEST_TABLE)?;
495 let iter = BucketRangeIterator::new(&table, &key_builder, 123u64, 0, 199)?;
496 assert_eq!(iter.bucket_range(), (0, 1));
497
498 let invalid_iter = BucketRangeIterator::new(&table, &key_builder, 123u64, 200, 100);
500 assert!(invalid_iter.is_err());
501 }
502
503 {
505 let read_txn = db.begin_read()?;
506 let table = read_txn.open_table(TEST_TABLE)?;
507 let iter = BucketRangeIterator::new(&table, &key_builder, 123u64, 0, 299)?;
508 let values: Vec<String> = iter.collect::<Result<_, _>>()?;
509 assert_eq!(
510 values,
511 vec![
512 "value_50".to_string(),
513 "value_150".to_string(),
514 "value_250".to_string()
515 ]
516 );
517
518 let iter = BucketRangeIterator::new(&table, &key_builder, 123u64, 0, 299)?;
519 let values: Vec<String> = iter.rev().collect::<Result<_, _>>()?;
520 assert_eq!(
521 values,
522 vec![
523 "value_250".to_string(),
524 "value_150".to_string(),
525 "value_50".to_string()
526 ]
527 );
528
529 let iter = table.bucket_range(&key_builder, 456u64, 0, 299)?;
530 let values: Vec<String> = iter.collect::<Result<_, _>>()?;
531 assert_eq!(
532 values,
533 vec!["other_50".to_string(), "other_150".to_string()]
534 );
535 }
536
537 Ok(())
538 }
539
540 #[test]
541 fn test_multimap_functionality() -> Result<(), Box<dyn std::error::Error>> {
542 let temp_file = NamedTempFile::new()?;
543 let db = Database::create(temp_file.path())?;
544 let key_builder = KeyBuilder::new(100)?;
545
546 {
547 let write_txn = db.begin_write()?;
548 {
549 let mut table = write_txn.open_multimap_table(TEST_MULTIMAP)?;
550
551 table.insert(key_builder.bucketed_key(123u64, 50), 10u64)?;
552 table.insert(key_builder.bucketed_key(123u64, 50), 20u64)?;
553 table.insert(key_builder.bucketed_key(123u64, 150), 30u64)?;
554 table.insert(key_builder.bucketed_key(123u64, 150), 40u64)?;
555
556 table.insert(key_builder.bucketed_key(456u64, 50), 99u64)?;
557 table.insert(key_builder.bucketed_key(456u64, 50), 100u64)?;
558 }
559 write_txn.commit()?;
560 }
561
562 {
563 let read_txn = db.begin_read()?;
564 let table = read_txn.open_multimap_table(TEST_MULTIMAP)?;
565 let iter = BucketRangeMultimapIterator::new(&table, &key_builder, 123u64, 0, 199)?;
566 assert_eq!(iter.bucket_range(), (0, 1));
567
568 let values: Vec<u64> = iter.collect::<Result<_, _>>()?;
569 assert_eq!(values, vec![10u64, 20u64, 30u64, 40u64]);
570
571 let iter = BucketRangeMultimapIterator::new(&table, &key_builder, 123u64, 0, 199)?;
572 let values: Vec<u64> = iter.rev().collect::<Result<_, _>>()?;
573 assert_eq!(values, vec![40u64, 30u64, 20u64, 10u64]);
574
575 let iter = table.bucket_range(&key_builder, 456u64, 0, 99)?;
576 let values: Vec<u64> = iter.collect::<Result<_, _>>()?;
577 assert_eq!(values, vec![99u64, 100u64]);
578 }
579
580 Ok(())
581 }
582}