use wbftree::{
BfTreeDeleteResult, BfTreeInsertResult, BfTreeReadResult, BfTreeService, ScanReturnField,
};
use crate::{
CollectionError, Result,
prefix::{TreePrefix, with_prefixed_key},
};
#[inline(always)]
fn project_entry<'a>(
return_field: ScanReturnField,
k: &'a [u8],
v: &'a [u8],
) -> (&'a [u8], &'a [u8]) {
match return_field {
ScanReturnField::Value => (&[], v),
ScanReturnField::Key => (&k[1..], &[]),
ScanReturnField::KeyAndValue => (&k[1..], v),
}
}
pub trait RiTreeOps {
fn ri_set(&self, sub_key: &[u8], val: &[u8]) -> Result<bool>;
fn ri_get(&self, sub_key: &[u8]) -> Result<Option<Vec<u8>>> {
self.ri_get_callback(sub_key, |opt| opt.map(|v| v.to_vec()))
}
fn ri_get_callback<R>(&self, sub_key: &[u8], f: impl FnOnce(Option<&[u8]>) -> R) -> Result<R>;
fn ri_del(&self, sub_key: &[u8]) -> Result<bool>;
fn ri_exists(&self, sub_key: &[u8]) -> Result<bool>;
fn ri_len(&self) -> Result<usize>;
fn ri_scan<F>(&self, start_key: &[u8], count: usize, on_entry: F) -> Result<usize>
where
F: FnMut(&[u8], &[u8]) -> bool,
{
self.ri_scan_with_field(start_key, count, ScanReturnField::KeyAndValue, on_entry)
}
fn ri_scan_with_field<F>(
&self,
start_key: &[u8],
count: usize,
return_field: ScanReturnField,
on_entry: F,
) -> Result<usize>
where
F: FnMut(&[u8], &[u8]) -> bool;
fn ri_range<F>(&self, start_key: &[u8], end_key: &[u8], on_entry: F) -> Result<usize>
where
F: FnMut(&[u8], &[u8]) -> bool,
{
self.ri_range_with_field(start_key, end_key, ScanReturnField::KeyAndValue, on_entry)
}
fn ri_range_with_field<F>(
&self,
start_key: &[u8],
end_key: &[u8],
return_field: ScanReturnField,
on_entry: F,
) -> Result<usize>
where
F: FnMut(&[u8], &[u8]) -> bool;
}
impl RiTreeOps for BfTreeService {
fn ri_set(&self, sub_key: &[u8], val: &[u8]) -> Result<bool> {
with_prefixed_key(TreePrefix::RangeIndexKey.as_u8(), sub_key, |k| {
let exists = self.contains_key(k);
match self.insert(k, val) {
BfTreeInsertResult::Success => Ok(!exists),
BfTreeInsertResult::InvalidKV => Err(CollectionError::KeyTooLong),
_ => Err(CollectionError::InvalidArgument("ri_set 插入失败")),
}
})
}
fn ri_get_callback<R>(&self, sub_key: &[u8], f: impl FnOnce(Option<&[u8]>) -> R) -> Result<R> {
with_prefixed_key(TreePrefix::RangeIndexKey.as_u8(), sub_key, |k| {
self.read_callback(k, |res, bytes| match res {
BfTreeReadResult::Found => Ok(f(Some(bytes))),
BfTreeReadResult::NotFound | BfTreeReadResult::Deleted => Ok(f(None)),
_ => Err(CollectionError::InvalidArgument("ri_get 读取失败")),
})
})
}
fn ri_del(&self, sub_key: &[u8]) -> Result<bool> {
with_prefixed_key(TreePrefix::RangeIndexKey.as_u8(), sub_key, |k| {
let exists = self.contains_key(k);
match self.delete(k) {
BfTreeDeleteResult::Success => Ok(exists),
_ => Err(CollectionError::InvalidArgument("ri_del 删除失败")),
}
})
}
#[inline]
fn ri_exists(&self, sub_key: &[u8]) -> Result<bool> {
with_prefixed_key(TreePrefix::RangeIndexKey.as_u8(), sub_key, |k| {
Ok(self.contains_key(k))
})
}
fn ri_len(&self) -> Result<usize> {
let prefix_u8 = TreePrefix::RangeIndexKey as u8;
let start_key = [prefix_u8];
let mut count = 0;
self.scan_with_count_callback(&start_key, usize::MAX, ScanReturnField::Key, |k, _| {
if k.is_empty() || k[0] != prefix_u8 {
return false;
}
count += 1;
true
})?;
Ok(count)
}
fn ri_scan_with_field<F>(
&self,
start_key: &[u8],
count: usize,
return_field: ScanReturnField,
mut on_entry: F,
) -> Result<usize>
where
F: FnMut(&[u8], &[u8]) -> bool,
{
if count == 0 {
return Ok(0);
}
let prefix_u8 = TreePrefix::RangeIndexKey.as_u8();
with_prefixed_key(prefix_u8, start_key, |sk| {
self
.scan_with_count_callback(sk, count, ScanReturnField::KeyAndValue, |k, v| {
if k.is_empty() || k[0] != prefix_u8 {
return false;
}
let (user_k, user_v) = project_entry(return_field, k, v);
on_entry(user_k, user_v)
})
.map_err(Into::into)
})
}
fn ri_range_with_field<F>(
&self,
start_key: &[u8],
end_key: &[u8],
return_field: ScanReturnField,
mut on_entry: F,
) -> Result<usize>
where
F: FnMut(&[u8], &[u8]) -> bool,
{
if start_key > end_key {
return Ok(0);
}
let prefix_u8 = TreePrefix::RangeIndexKey.as_u8();
with_prefixed_key(prefix_u8, start_key, |sk| {
with_prefixed_key(prefix_u8, end_key, |ek| {
self
.scan_with_end_key_callback(sk, ek, ScanReturnField::KeyAndValue, |k, v| {
if k.is_empty() || k[0] != prefix_u8 {
return false;
}
let (user_k, user_v) = project_entry(return_field, k, v);
on_entry(user_k, user_v)
})
.map_err(Into::into)
})
})
}
}