pub(crate) mod helpers;
pub(crate) mod seekable;
use std::fmt::Debug;
use serde::de::DeserializeOwned;
use crate::error::StoreError;
use crate::iter::seekable::SeekableRows;
use crate::types::IterationControlDecision;
pub enum IterationMode<'cfg_lt, OutK, OutV> {
Deserialize(Box<dyn FnMut(&[u8], &[u8]) -> Result<(OutK, OutV), StoreError> + 'cfg_lt>),
Raw,
ControlOnly,
}
pub enum IterationResult<'iter_lt, OutK, OutV> {
EffectCompleted,
RawItems(Box<dyn Iterator<Item = Result<(Vec<u8>, Vec<u8>), StoreError>> + 'iter_lt>),
DeserializedItems(Box<dyn Iterator<Item = Result<(OutK, OutV), StoreError>> + 'iter_lt>),
}
pub struct IterConfig<'cfg_lt, SerKey, OutK, OutV> {
pub cf_name: String,
pub prefix: Option<SerKey>,
pub start: Option<SerKey>,
pub reverse: bool,
pub control: Option<Box<dyn FnMut(&[u8], &[u8], usize) -> IterationControlDecision + 'cfg_lt>>,
pub mode: IterationMode<'cfg_lt, OutK, OutV>,
_phantom_cfg_lt: std::marker::PhantomData<&'cfg_lt ()>,
}
impl<'cfg_lt, SerKey, OutK, OutV> IterConfig<'cfg_lt, SerKey, OutK, OutV> {
pub fn new_deserializing(
cf_name: String,
prefix: Option<SerKey>,
start: Option<SerKey>,
reverse: bool,
control: Option<Box<dyn FnMut(&[u8], &[u8], usize) -> IterationControlDecision + 'cfg_lt>>,
deserializer: Box<dyn FnMut(&[u8], &[u8]) -> Result<(OutK, OutV), StoreError> + 'cfg_lt>,
) -> Self {
Self {
cf_name,
prefix,
start,
reverse,
control,
mode: IterationMode::Deserialize(deserializer),
_phantom_cfg_lt: std::marker::PhantomData,
}
}
}
impl<'cfg_lt, SerKey> IterConfig<'cfg_lt, SerKey, Vec<u8>, Vec<u8>> {
pub fn new_raw(
cf_name: String,
prefix: Option<SerKey>,
start: Option<SerKey>,
reverse: bool,
control: Option<Box<dyn FnMut(&[u8], &[u8], usize) -> IterationControlDecision + 'cfg_lt>>,
) -> Self {
Self {
cf_name,
prefix,
start,
reverse,
control,
mode: IterationMode::Raw,
_phantom_cfg_lt: std::marker::PhantomData,
}
}
}
impl<'cfg_lt, SerKey> IterConfig<'cfg_lt, SerKey, (), ()> {
pub fn new_control_only(
cf_name: String,
prefix: Option<SerKey>,
start: Option<SerKey>,
reverse: bool,
control: Box<dyn FnMut(&[u8], &[u8], usize) -> IterationControlDecision + 'cfg_lt>,
) -> Self {
Self {
cf_name,
prefix,
start,
reverse,
control: Some(control),
mode: IterationMode::ControlOnly,
_phantom_cfg_lt: std::marker::PhantomData,
}
}
}
pub(crate) struct ControlledIter<'iter_lt, R, OutK, OutV>
where
R: SeekableRows + 'iter_lt,
OutK: DeserializeOwned + Debug + 'iter_lt,
OutV: DeserializeOwned + Debug + 'iter_lt,
{
pub(crate) raw: R,
pub(crate) reverse: bool,
pub(crate) control: Option<Box<dyn FnMut(&[u8], &[u8], usize) -> IterationControlDecision + 'iter_lt>>,
pub(crate) deserializer: Box<dyn FnMut(&[u8], &[u8]) -> Result<(OutK, OutV), StoreError> + 'iter_lt>,
pub(crate) items_kept_count: usize,
pub(crate) _phantom_out: std::marker::PhantomData<(OutK, OutV)>, }
impl<'iter_lt, R, OutK, OutV> Iterator for ControlledIter<'iter_lt, R, OutK, OutV>
where
R: SeekableRows + 'iter_lt,
OutK: DeserializeOwned + Debug + 'iter_lt,
OutV: DeserializeOwned + Debug + 'iter_lt,
{
type Item = Result<(OutK, OutV), StoreError>;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.raw.next() {
Some(Ok((key_bytes, val_bytes))) => {
if let Some(ref mut control_fn) = self.control {
match control_fn(&key_bytes, &val_bytes, self.items_kept_count) {
IterationControlDecision::Stop => return None,
IterationControlDecision::Skip => {
continue;
}
IterationControlDecision::Keep => {}
IterationControlDecision::SeekTo(target) => {
if !seek_advances(&target, &key_bytes, self.reverse) {
return None; }
self.raw.seek_to(&target, self.reverse);
continue;
}
}
}
let deserialized_item = (self.deserializer)(&key_bytes, &val_bytes);
self.items_kept_count += 1;
return Some(deserialized_item);
}
Some(Err(e)) => return Some(Err(StoreError::RocksDb(e))),
None => return None,
}
}
}
}
pub(crate) fn seek_advances(target: &[u8], current: &[u8], reverse: bool) -> bool {
let advances = if reverse {
target < current
} else {
target > current
};
if !advances {
log::debug!(
"rocksolid iteration: SeekTo target did not advance the cursor (reverse={reverse}); treating as Stop"
);
}
advances
}