use crate::DBAndColumns;
use owning_ref::{OwningHandle, StableAddress};
use parking_lot::RwLockReadGuard;
use rocksdb::{DBIterator, Direction, IteratorMode, ReadOptions};
use std::ops::{Deref, DerefMut};
pub type KeyValuePair = (Box<[u8]>, Box<[u8]>);
pub struct ReadGuardedIterator<'a, I, T> {
inner: OwningHandle<UnsafeStableAddress<'a, Option<T>>, DerefWrapper<Option<I>>>,
}
#[repr(transparent)]
struct UnsafeStableAddress<'a, T>(RwLockReadGuard<'a, T>);
impl<'a, T> Deref for UnsafeStableAddress<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
unsafe impl<'a, T> StableAddress for UnsafeStableAddress<'a, T> {}
struct DerefWrapper<T>(T);
impl<T> Deref for DerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for DerefWrapper<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'a, I: Iterator, T> Iterator for ReadGuardedIterator<'a, I, T> {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
self.inner.deref_mut().as_mut().and_then(|iter| iter.next())
}
}
pub trait IterationHandler {
type Iterator: Iterator<Item = KeyValuePair>;
fn iter(&self, col: u32, read_opts: ReadOptions) -> Self::Iterator;
fn iter_with_prefix(&self, col: u32, prefix: &[u8], read_opts: ReadOptions) -> Self::Iterator;
}
impl<'a, T> ReadGuardedIterator<'a, <&'a T as IterationHandler>::Iterator, T>
where
&'a T: IterationHandler,
{
pub fn new(read_lock: RwLockReadGuard<'a, Option<T>>, col: u32, read_opts: ReadOptions) -> Self {
Self { inner: Self::new_inner(read_lock, |db| db.iter(col, read_opts)) }
}
pub fn new_with_prefix(
read_lock: RwLockReadGuard<'a, Option<T>>,
col: u32,
prefix: &[u8],
read_opts: ReadOptions,
) -> Self {
Self { inner: Self::new_inner(read_lock, |db| db.iter_with_prefix(col, prefix, read_opts)) }
}
fn new_inner(
rlock: RwLockReadGuard<'a, Option<T>>,
f: impl FnOnce(&'a T) -> <&'a T as IterationHandler>::Iterator,
) -> OwningHandle<UnsafeStableAddress<'a, Option<T>>, DerefWrapper<Option<<&'a T as IterationHandler>::Iterator>>> {
OwningHandle::new_with_fn(UnsafeStableAddress(rlock), move |rlock| {
let rlock = unsafe { rlock.as_ref().expect("initialized as non-null; qed") };
DerefWrapper(rlock.as_ref().map(f))
})
}
}
impl<'a> IterationHandler for &'a DBAndColumns {
type Iterator = DBIterator<'a>;
fn iter(&self, col: u32, read_opts: ReadOptions) -> Self::Iterator {
self.db.iterator_cf_opt(self.cf(col as usize), read_opts, IteratorMode::Start)
}
fn iter_with_prefix(&self, col: u32, prefix: &[u8], read_opts: ReadOptions) -> Self::Iterator {
self.db
.iterator_cf_opt(self.cf(col as usize), read_opts, IteratorMode::From(prefix, Direction::Forward))
}
}