use crate::db::{Result, DB};
use crate::range::{RangeItem, RangeIterator, RangeIteratorRev};
use std::error::Error;
pub struct Scan<'db> {
db: &'db DB,
start: Option<Vec<u8>>,
end: Option<Vec<u8>>,
prefix: Option<Vec<u8>>,
keys_only: bool,
reverse: bool,
}
impl<'db> Scan<'db> {
pub(crate) const fn new(db: &'db DB) -> Self {
Self {
db,
start: None,
end: None,
prefix: None,
keys_only: false,
reverse: false,
}
}
#[must_use]
pub fn range(mut self, start: &[u8], end: &[u8]) -> Self {
self.start = Some(start.to_vec());
self.end = Some(end.to_vec());
self.prefix = None;
self
}
#[must_use]
pub fn from(mut self, start: &[u8]) -> Self {
self.start = Some(start.to_vec());
self.end = None;
self.prefix = None;
self
}
#[must_use]
pub fn prefix(mut self, prefix: &[u8]) -> Self {
self.prefix = Some(prefix.to_vec());
self.start = None;
self.end = None;
self
}
#[must_use]
pub const fn keys_only(mut self) -> Self {
self.keys_only = true;
self
}
#[must_use]
pub const fn reverse(mut self) -> Self {
self.reverse = true;
self
}
pub fn iter(self) -> Result<ScanIterator> {
if self.reverse {
let (start, end) = self.resolve_bounds();
let iter = if self.keys_only {
self.db.range_keys_only_rev(&start, end.as_deref())?
} else {
self.db.range_rev(&start, end.as_deref())?
};
Ok(ScanIterator::Reverse(iter))
} else {
let (start, end) = self.resolve_bounds();
let iter = if self.keys_only {
self.db.range_keys_only(&start, end.as_deref())?
} else {
self.db.range(&start, end.as_deref())?
};
Ok(ScanIterator::Forward(iter))
}
}
fn resolve_bounds(&self) -> (Vec<u8>, Option<Vec<u8>>) {
if let Some(ref prefix) = self.prefix {
let mut end = prefix.clone();
if let Some(last) = end.last_mut() {
if *last < 0xFF {
*last += 1;
} else {
end.push(0x00);
}
}
(prefix.clone(), Some(end))
} else {
let start = self.start.clone().unwrap_or_default();
let end = self.end.clone();
(start, end)
}
}
}
pub enum ScanIterator {
Forward(RangeIterator),
Reverse(RangeIteratorRev),
}
impl Iterator for ScanIterator {
type Item = std::result::Result<RangeItem, Box<dyn Error>>;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::Forward(iter) => iter.next(),
Self::Reverse(iter) => iter.next(),
}
}
}