use wbftree::{BfTreeDeleteResult, BfTreeInsertResult, BfTreeService, ScanReturnField};
use crate::{
CollectionError, Result,
prefix::{TreePrefix, with_prefixed_key},
};
pub const SET_VAL_PLACEHOLDER: &[u8] = &[0x00; 4];
pub trait SetTreeOps {
fn sadd(&self, member: &[u8]) -> Result<bool>;
fn srem(&self, member: &[u8]) -> Result<bool>;
fn sismember(&self, member: &[u8]) -> Result<bool>;
fn scard(&self) -> Result<usize>;
fn sscan<F>(&self, start_member: &[u8], count: usize, on_member: F) -> Result<usize>
where
F: FnMut(&[u8]) -> bool;
fn smembers(&self) -> Result<Vec<Vec<u8>>> {
let mut members = Vec::new();
self.sscan(b"", usize::MAX, |m| {
members.push(m.to_vec());
true
})?;
Ok(members)
}
}
impl SetTreeOps for BfTreeService {
fn sadd(&self, member: &[u8]) -> Result<bool> {
with_prefixed_key(TreePrefix::SetMember.as_u8(), member, |k| {
let exists = self.contains_key(k);
if exists {
return Ok(false);
}
match self.insert(k, SET_VAL_PLACEHOLDER) {
BfTreeInsertResult::Success => Ok(true),
BfTreeInsertResult::InvalidKV => Err(CollectionError::KeyTooLong),
_ => Err(CollectionError::InvalidArgument("sadd 插入失败")),
}
})
}
fn srem(&self, member: &[u8]) -> Result<bool> {
with_prefixed_key(TreePrefix::SetMember.as_u8(), member, |k| {
let exists = self.contains_key(k);
if !exists {
return Ok(false);
}
match self.delete(k) {
BfTreeDeleteResult::Success => Ok(true),
_ => Err(CollectionError::InvalidArgument("srem 删除失败")),
}
})
}
#[inline]
fn sismember(&self, member: &[u8]) -> Result<bool> {
with_prefixed_key(TreePrefix::SetMember.as_u8(), member, |k| {
Ok(self.contains_key(k))
})
}
fn scard(&self) -> Result<usize> {
let prefix_u8 = TreePrefix::SetMember.as_u8();
let start_key = [prefix_u8];
let mut count = 0;
self.scan_with_count_callback(&start_key, usize::MAX, ScanReturnField::Key, |k, _val| {
if k.is_empty() || k[0] != prefix_u8 {
return false;
}
count += 1;
true
})?;
Ok(count)
}
fn sscan<F>(&self, start_member: &[u8], count: usize, mut on_member: F) -> Result<usize>
where
F: FnMut(&[u8]) -> bool,
{
if count == 0 {
return Ok(0);
}
let prefix_u8 = TreePrefix::SetMember.as_u8();
with_prefixed_key(prefix_u8, start_member, |sk| {
self
.scan_with_count_callback(sk, count, ScanReturnField::Key, |k, _| {
if k.is_empty() || k[0] != prefix_u8 {
return false;
}
on_member(&k[1..])
})
.map_err(Into::into)
})
}
}