use core::{cmp::Ordering, iter::FusedIterator, ops::Deref, ptr, result::Result as StdResult};
use crate::{
error::{Error, Result},
simd::fast_key_eq,
zset::{decode_order_preserving_f64, encode_order_preserving_f64},
};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ZSetEntryRef<'a> {
pub score: f64,
pub order_score: [u8; 8],
pub member: &'a [u8],
}
impl<'a> Deref for ZSetEntryRef<'a> {
type Target = [u8];
#[inline(always)]
fn deref(&self) -> &Self::Target {
self.member
}
}
impl<'a> AsRef<[u8]> for ZSetEntryRef<'a> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self.member
}
}
#[derive(Debug, Clone)]
pub struct CompactZSetIter<'a> {
slice: &'a [u8],
offset: usize,
remaining: usize,
}
impl<'a> Iterator for CompactZSetIter<'a> {
type Item = ZSetEntryRef<'a>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 || self.offset >= self.slice.len() {
return None;
}
let (entry_len, entry) = CompactZSetCodec::parse_entry(self.slice, self.offset).ok()?;
self.offset += entry_len;
self.remaining -= 1;
Some(entry)
}
#[inline(always)]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<'a> ExactSizeIterator for CompactZSetIter<'a> {
#[inline(always)]
fn len(&self) -> usize {
self.remaining
}
}
impl<'a> FusedIterator for CompactZSetIter<'a> {}
pub type CompactZSetRangeIter<'a> = CompactZSetIter<'a>;
pub const COMPACT_ZSET_COUNT_SIZE: usize = 2;
pub const COMPACT_ZSET_SCORE_SIZE: usize = 8;
pub const COMPACT_ZSET_LEN_SIZE: usize = 2;
pub const COMPACT_ZSET_ENTRY_HEADER_SIZE: usize = COMPACT_ZSET_SCORE_SIZE + COMPACT_ZSET_LEN_SIZE;
pub struct CompactZSetCodec;
impl CompactZSetCodec {
#[inline]
pub fn count(slice: &[u8]) -> Result<usize> {
if slice.len() < COMPACT_ZSET_COUNT_SIZE {
return Err(Error::BufferTooShort {
expected: COMPACT_ZSET_COUNT_SIZE,
actual: slice.len(),
});
}
Ok(u16::from_be_bytes([slice[0], slice[1]]) as usize)
}
#[inline]
pub fn parse_entry(slice: &[u8], offset: usize) -> Result<(usize, ZSetEntryRef<'_>)> {
let (total_len, order_score, member) = Self::parse_entry_header(slice, offset)?;
let score = decode_order_preserving_f64(order_score);
Ok((
total_len,
ZSetEntryRef {
score,
order_score,
member,
},
))
}
#[inline(always)]
pub fn parse_entry_header(slice: &[u8], offset: usize) -> Result<(usize, [u8; 8], &[u8])> {
let header_end = match offset.checked_add(COMPACT_ZSET_ENTRY_HEADER_SIZE) {
Some(end) if end <= slice.len() => end,
_ => {
return Err(Error::BufferTooShort {
expected: offset + COMPACT_ZSET_ENTRY_HEADER_SIZE,
actual: slice.len(),
});
}
};
unsafe {
let ptr = slice.as_ptr().add(offset);
let order_score = (ptr as *const [u8; COMPACT_ZSET_SCORE_SIZE]).read_unaligned();
let m_len = u16::from_be_bytes(
(ptr.add(COMPACT_ZSET_SCORE_SIZE) as *const [u8; COMPACT_ZSET_LEN_SIZE]).read_unaligned(),
) as usize;
let total_len = match COMPACT_ZSET_ENTRY_HEADER_SIZE.checked_add(m_len) {
Some(l) => l,
None => return Err(Error::RecordSizeOverflow),
};
let m_end = match header_end.checked_add(m_len) {
Some(end) if end <= slice.len() => end,
_ => {
return Err(Error::BufferTooShort {
expected: header_end.saturating_add(m_len),
actual: slice.len(),
});
}
};
Ok((
total_len,
order_score,
slice.get_unchecked(header_end..m_end),
))
}
}
pub fn validate(slice: &[u8]) -> Result<usize> {
let count = Self::count(slice)?;
let mut offset = 2;
let mut prev: Option<([u8; 8], &[u8])> = None;
for _ in 0..count {
let (entry_len, order_score, member) = Self::parse_entry_header(slice, offset)?;
if let Some((prev_order, prev_member)) = prev {
let ord = prev_order
.cmp(&order_score)
.then_with(|| prev_member.cmp(member));
if ord != Ordering::Less {
return Err(Error::CorruptedCompactData(
"紧凑有序集合成员未按严格保序递增排列或存在重复项",
));
}
}
prev = Some((order_score, member));
offset += entry_len;
}
if offset != slice.len() {
return Err(Error::BufferTooShort {
expected: offset,
actual: slice.len(),
});
}
Ok(count)
}
#[inline]
fn collect_offsets<F, R>(slice: &[u8], count: usize, f: F) -> Result<R>
where
F: FnOnce(&[usize]) -> R,
{
const STACK_CAP: usize = 256;
if count <= STACK_CAP {
let mut stack_offsets = [0usize; STACK_CAP];
let mut offset = 2;
for slot in stack_offsets.iter_mut().take(count) {
*slot = offset;
let (entry_len, ..) = Self::parse_entry_header(slice, offset)?;
offset += entry_len;
}
Ok(f(&stack_offsets[..count]))
} else {
let mut heap_offsets = Vec::with_capacity(count);
let mut offset = 2;
for _ in 0..count {
heap_offsets.push(offset);
let (entry_len, ..) = Self::parse_entry_header(slice, offset)?;
offset += entry_len;
}
Ok(f(&heap_offsets))
}
}
#[inline]
pub fn binary_search_offsets(
slice: &[u8],
offsets: &[usize],
order_score: [u8; 8],
member: &[u8],
) -> Result<StdResult<usize, usize>> {
let mut low = 0;
let mut high = offsets.len();
while low < high {
let mid = (low + high) / 2;
let (_, entry_order, m) = Self::parse_entry_header(slice, offsets[mid])?;
let ord = entry_order.cmp(&order_score).then_with(|| m.cmp(member));
match ord {
Ordering::Less => low = mid + 1,
Ordering::Greater => high = mid,
Ordering::Equal => return Ok(Ok(mid)),
}
}
Ok(Err(low))
}
pub fn binary_search_entry(
slice: &[u8],
order_score: [u8; 8],
member: &[u8],
) -> Result<StdResult<usize, usize>> {
if slice.len() < 2 {
return Ok(Err(0));
}
let count = Self::count(slice)?;
if count == 0 {
return Ok(Err(0));
}
Self::collect_offsets(slice, count, |offsets| {
Self::binary_search_offsets(slice, offsets, order_score, member)
})
.and_then(|found| found)
}
pub fn rank_of(slice: &[u8], member: &[u8]) -> Option<usize> {
if slice.len() < COMPACT_ZSET_COUNT_SIZE {
return None;
}
let count = u16::from_be_bytes([slice[0], slice[1]]) as usize;
let mut offset = COMPACT_ZSET_COUNT_SIZE;
for rank in 0..count {
let (entry_len, _, m) = Self::parse_entry_header(slice, offset).ok()?;
if fast_key_eq(m, member) {
return Some(rank);
}
offset += entry_len;
}
None
}
pub fn key_at_rank(slice: &[u8], rank: usize) -> Option<&[u8]> {
if slice.len() < COMPACT_ZSET_COUNT_SIZE {
return None;
}
let count = u16::from_be_bytes([slice[0], slice[1]]) as usize;
if rank >= count {
return None;
}
let mut offset = COMPACT_ZSET_COUNT_SIZE;
for cur_rank in 0..count {
let (entry_len, _, m) = Self::parse_entry_header(slice, offset).ok()?;
if cur_rank == rank {
return Some(m);
}
offset += entry_len;
}
None
}
pub fn entry_at_rank<'a>(slice: &'a [u8], rank: usize) -> Option<ZSetEntryRef<'a>> {
if slice.len() < COMPACT_ZSET_COUNT_SIZE {
return None;
}
let count = u16::from_be_bytes([slice[0], slice[1]]) as usize;
if rank >= count {
return None;
}
let mut offset = COMPACT_ZSET_COUNT_SIZE;
for cur_rank in 0..count {
let (entry_len, entry) = Self::parse_entry(slice, offset).ok()?;
if cur_rank == rank {
return Some(entry);
}
offset += entry_len;
}
None
}
pub fn score_of(slice: &[u8], member: &[u8]) -> Option<f64> {
if slice.len() < COMPACT_ZSET_COUNT_SIZE {
return None;
}
let count = u16::from_be_bytes([slice[0], slice[1]]) as usize;
let mut offset = COMPACT_ZSET_COUNT_SIZE;
for _ in 0..count {
let (entry_len, order_score, m) = Self::parse_entry_header(slice, offset).ok()?;
if fast_key_eq(m, member) {
let score = decode_order_preserving_f64(order_score);
return Some(score);
}
offset += entry_len;
}
None
}
pub fn insert(buf: &mut Vec<u8>, score: f64, member: &[u8]) -> Result<bool> {
if member.len() > u16::MAX as usize {
return Err(Error::KeyLengthOverflow(member.len()));
}
if buf.is_empty() {
buf.extend_from_slice(&0u16.to_be_bytes());
} else if buf.len() < COMPACT_ZSET_COUNT_SIZE {
return Err(Error::BufferTooShort {
expected: COMPACT_ZSET_COUNT_SIZE,
actual: buf.len(),
});
}
let order_score = encode_order_preserving_f64(score);
let count = u16::from_be_bytes([buf[0], buf[1]]) as usize;
if count == 0 {
buf.truncate(COMPACT_ZSET_COUNT_SIZE);
}
const STACK_CAP: usize = 256;
let mut stack_offsets = [0usize; STACK_CAP];
let mut existing_found = None;
let mut offset = COMPACT_ZSET_COUNT_SIZE;
if count <= STACK_CAP {
for slot in stack_offsets.iter_mut().take(count) {
*slot = offset;
let (entry_len, entry_order, m) = Self::parse_entry_header(buf, offset)?;
if fast_key_eq(m, member) {
existing_found = Some((offset, entry_len, entry_order));
break;
}
offset += entry_len;
}
} else {
for _ in 0..count {
let (entry_len, entry_order, m) = Self::parse_entry_header(buf, offset)?;
if fast_key_eq(m, member) {
existing_found = Some((offset, entry_len, entry_order));
break;
}
offset += entry_len;
}
}
let is_new = if let Some((old_offset, old_len, old_order_score)) = existing_found {
if old_order_score == order_score {
return Ok(false);
}
buf.drain(old_offset..old_offset + old_len);
let new_count = (count - 1) as u16;
buf[0..COMPACT_ZSET_COUNT_SIZE].copy_from_slice(&new_count.to_be_bytes());
false
} else {
true
};
let count_after_del = u16::from_be_bytes([buf[0], buf[1]]) as usize;
if count_after_del >= u16::MAX as usize {
return Err(Error::CompactCountOverflow(count_after_del + 1));
}
let insert_offset = if count_after_del == 0 {
buf.len()
} else if is_new && count_after_del <= STACK_CAP {
let insert_idx = match Self::binary_search_offsets(
buf,
&stack_offsets[..count_after_del],
order_score,
member,
)? {
Ok(idx) | Err(idx) => idx,
};
if insert_idx == count_after_del {
buf.len()
} else {
stack_offsets[insert_idx]
}
} else {
Self::collect_offsets(buf, count_after_del, |offsets| {
Self::binary_search_offsets(buf, offsets, order_score, member).map(|found| {
let idx = match found {
Ok(idx) | Err(idx) => idx,
};
if idx == count_after_del {
buf.len()
} else {
offsets[idx]
}
})
})??
};
let new_entry_len = COMPACT_ZSET_ENTRY_HEADER_SIZE + member.len();
let old_len = buf.len();
buf.reserve(new_entry_len);
if insert_offset == old_len {
buf.extend_from_slice(&order_score);
buf.extend_from_slice(&(member.len() as u16).to_be_bytes());
buf.extend_from_slice(member);
} else {
unsafe {
let p = buf.as_mut_ptr();
ptr::copy(
p.add(insert_offset),
p.add(insert_offset + new_entry_len),
old_len - insert_offset,
);
ptr::copy_nonoverlapping(
order_score.as_ptr(),
p.add(insert_offset),
COMPACT_ZSET_SCORE_SIZE,
);
ptr::copy_nonoverlapping(
(member.len() as u16).to_be_bytes().as_ptr(),
p.add(insert_offset + COMPACT_ZSET_SCORE_SIZE),
COMPACT_ZSET_LEN_SIZE,
);
ptr::copy_nonoverlapping(
member.as_ptr(),
p.add(insert_offset + COMPACT_ZSET_ENTRY_HEADER_SIZE),
member.len(),
);
buf.set_len(old_len + new_entry_len);
}
}
let final_count = (count_after_del + 1) as u16;
buf[0..COMPACT_ZSET_COUNT_SIZE].copy_from_slice(&final_count.to_be_bytes());
Ok(is_new)
}
pub fn remove(buf: &mut Vec<u8>, member: &[u8]) -> Result<bool> {
if buf.len() < COMPACT_ZSET_COUNT_SIZE {
return Ok(false);
}
let count = u16::from_be_bytes([buf[0], buf[1]]) as usize;
if count == 0 {
return Ok(false);
}
let mut offset = COMPACT_ZSET_COUNT_SIZE;
for _ in 0..count {
let (entry_len, _, m) = Self::parse_entry_header(buf, offset)?;
if fast_key_eq(m, member) {
buf.copy_within(offset + entry_len.., offset);
buf.truncate(buf.len() - entry_len);
let new_count = (count - 1) as u16;
buf[0..COMPACT_ZSET_COUNT_SIZE].copy_from_slice(&new_count.to_be_bytes());
return Ok(true);
}
offset += entry_len;
}
Ok(false)
}
#[inline(always)]
fn score_at(slice: &[u8], off: usize) -> [u8; COMPACT_ZSET_SCORE_SIZE] {
unsafe { (slice.as_ptr().add(off) as *const [u8; COMPACT_ZSET_SCORE_SIZE]).read_unaligned() }
}
fn score_range_span(
slice: &[u8],
count: usize,
min: f64,
min_inclusive: bool,
max: f64,
max_inclusive: bool,
) -> Result<(usize, usize)> {
let min_order = encode_order_preserving_f64(min);
let max_order = encode_order_preserving_f64(max);
if min_order > max_order || (min_order == max_order && (!min_inclusive || !max_inclusive)) {
return Ok((slice.len(), 0));
}
Self::collect_offsets(slice, count, |offsets| {
let mut low = 0;
let mut high = count;
while low < high {
let mid = (low + high) / 2;
let entry_order = Self::score_at(slice, offsets[mid]);
let satisfies = if min_inclusive {
entry_order >= min_order
} else {
entry_order > min_order
};
if !satisfies {
low = mid + 1;
} else {
high = mid;
}
}
let start_idx = low;
let mut right_low = start_idx;
let mut high = count;
while right_low < high {
let mid = (right_low + high) / 2;
let entry_order = Self::score_at(slice, offsets[mid]);
let exceeds = if max_inclusive {
entry_order > max_order
} else {
entry_order >= max_order
};
if !exceeds {
right_low = mid + 1;
} else {
high = mid;
}
}
let end_idx = right_low;
let start_offset = if start_idx < count {
offsets[start_idx]
} else {
slice.len()
};
(start_offset, end_idx.saturating_sub(start_idx))
})
}
#[inline(always)]
pub fn count_range(slice: &[u8], min: f64, max: f64) -> usize {
Self::count_score_range(slice, min, true, max, true)
}
pub fn count_score_range(
slice: &[u8],
min: f64,
min_inclusive: bool,
max: f64,
max_inclusive: bool,
) -> usize {
if slice.len() < 2 {
return 0;
}
let count = match Self::count(slice) {
Ok(c) if c > 0 => c,
_ => return 0,
};
Self::score_range_span(slice, count, min, min_inclusive, max, max_inclusive)
.map_or(0, |(_, remaining)| remaining)
}
#[inline(always)]
pub fn range(slice: &[u8], min: f64, max: f64) -> CompactZSetRangeIter<'_> {
Self::range_with_options(slice, min, true, max, true)
}
pub fn range_with_options(
slice: &[u8],
min: f64,
min_inclusive: bool,
max: f64,
max_inclusive: bool,
) -> CompactZSetRangeIter<'_> {
let empty_iter = CompactZSetRangeIter {
slice,
offset: slice.len(),
remaining: 0,
};
if slice.len() < 2 {
return empty_iter;
}
let count = match Self::count(slice) {
Ok(c) if c > 0 => c,
_ => return empty_iter,
};
match Self::score_range_span(slice, count, min, min_inclusive, max, max_inclusive) {
Ok((start_offset, remaining)) => CompactZSetRangeIter {
slice,
offset: start_offset,
remaining,
},
Err(_) => empty_iter,
}
}
#[inline]
pub fn iter_members(slice: &[u8]) -> CompactZSetIter<'_> {
let count = if slice.len() >= COMPACT_ZSET_COUNT_SIZE {
u16::from_be_bytes([slice[0], slice[1]]) as usize
} else {
0
};
CompactZSetIter {
slice,
offset: COMPACT_ZSET_COUNT_SIZE,
remaining: count,
}
}
pub fn encode<'a, I>(entries: I) -> Result<Vec<u8>>
where
I: IntoIterator<Item = (f64, &'a [u8])>,
{
let mut items: Vec<([u8; COMPACT_ZSET_SCORE_SIZE], &[u8])> = entries
.into_iter()
.map(|(score, member)| {
if member.len() > u16::MAX as usize {
return Err(Error::KeyLengthOverflow(member.len()));
}
Ok((encode_order_preserving_f64(score), member))
})
.collect::<Result<_>>()?;
items.sort_by(|a, b| a.1.cmp(b.1));
items.reverse();
items.dedup_by(|a, b| a.1 == b.1);
items.reverse();
if items.len() > u16::MAX as usize {
return Err(Error::CompactCountOverflow(items.len()));
}
items.sort_unstable_by(|a, b| a.0.cmp(&b.0).then_with(|| a.1.cmp(b.1)));
let payload_len: usize = items
.iter()
.map(|(_, m)| COMPACT_ZSET_ENTRY_HEADER_SIZE + m.len())
.sum();
let mut buf = Vec::with_capacity(COMPACT_ZSET_COUNT_SIZE + payload_len);
buf.extend_from_slice(&(items.len() as u16).to_be_bytes());
for (order_score, member) in items {
buf.extend_from_slice(&order_score);
buf.extend_from_slice(&(member.len() as u16).to_be_bytes());
buf.extend_from_slice(member);
}
Ok(buf)
}
}
#[derive(Debug, Clone, PartialEq, Default)]
pub struct CompactZSet {
raw: Vec<u8>,
}
impl CompactZSet {
#[inline]
pub fn new() -> Self {
Self {
raw: vec![0u8, 0u8],
}
}
#[inline]
pub fn with_capacity(cap: usize) -> Self {
let mut raw = Vec::with_capacity(cap.max(2));
raw.extend_from_slice(&0u16.to_be_bytes());
Self { raw }
}
#[inline]
pub fn from_vec(raw: Vec<u8>) -> Result<Self> {
if raw.len() < 2 {
return Err(Error::BufferTooShort {
expected: 2,
actual: raw.len(),
});
}
let _ = CompactZSetCodec::validate(&raw)?;
Ok(Self { raw })
}
#[inline(always)]
pub fn as_slice(&self) -> &[u8] {
&self.raw
}
#[inline(always)]
pub fn into_vec(self) -> Vec<u8> {
self.raw
}
#[inline(always)]
pub fn len(&self) -> usize {
CompactZSetCodec::count(&self.raw).unwrap_or(0)
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline(always)]
pub fn rank_of(&self, member: &[u8]) -> Option<usize> {
CompactZSetCodec::rank_of(&self.raw, member)
}
#[inline(always)]
pub fn key_at_rank(&self, rank: usize) -> Option<&[u8]> {
CompactZSetCodec::key_at_rank(&self.raw, rank)
}
#[inline(always)]
pub fn score_of(&self, member: &[u8]) -> Option<f64> {
CompactZSetCodec::score_of(&self.raw, member)
}
#[inline(always)]
pub fn insert(&mut self, score: f64, member: &[u8]) -> Result<bool> {
CompactZSetCodec::insert(&mut self.raw, score, member)
}
#[inline(always)]
pub fn remove(&mut self, member: &[u8]) -> Result<bool> {
CompactZSetCodec::remove(&mut self.raw, member)
}
#[inline(always)]
pub fn count_range(&self, min: f64, max: f64) -> usize {
CompactZSetCodec::count_range(&self.raw, min, max)
}
#[inline(always)]
pub fn count_score_range(
&self,
min: f64,
min_inclusive: bool,
max: f64,
max_inclusive: bool,
) -> usize {
CompactZSetCodec::count_score_range(&self.raw, min, min_inclusive, max, max_inclusive)
}
#[inline(always)]
pub fn range(&self, min: f64, max: f64) -> CompactZSetRangeIter<'_> {
CompactZSetCodec::range(&self.raw, min, max)
}
#[inline(always)]
pub fn range_with_options(
&self,
min: f64,
min_inclusive: bool,
max: f64,
max_inclusive: bool,
) -> CompactZSetRangeIter<'_> {
CompactZSetCodec::range_with_options(&self.raw, min, min_inclusive, max, max_inclusive)
}
#[inline(always)]
pub fn iter_members(&self) -> CompactZSetIter<'_> {
CompactZSetCodec::iter_members(&self.raw)
}
#[inline]
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
Self::from_vec(bytes.to_vec())
}
#[inline(always)]
pub fn as_bytes(&self) -> &[u8] {
self.as_slice()
}
#[inline(always)]
pub fn zcard(&self) -> usize {
self.len()
}
#[inline(always)]
pub fn zrank(&self, member: &[u8]) -> Option<usize> {
self.rank_of(member)
}
#[inline(always)]
pub fn zrevrank(&self, member: &[u8]) -> Option<usize> {
self.rank_of(member).map(|r| self.len() - 1 - r)
}
#[inline(always)]
pub fn zscore(&self, member: &[u8]) -> Option<f64> {
self.score_of(member)
}
#[inline]
pub fn clear(&mut self) {
self.raw.clear();
self.raw.extend_from_slice(&0u16.to_be_bytes());
self.raw.shrink_to_fit();
}
pub fn pop_min(&mut self) -> Option<(Vec<u8>, f64)> {
if self.is_empty() {
return None;
}
let (entry_len, entry) =
CompactZSetCodec::parse_entry(&self.raw, COMPACT_ZSET_COUNT_SIZE).ok()?;
let member = entry.member.to_vec();
let score = entry.score;
self.raw.copy_within(
COMPACT_ZSET_COUNT_SIZE + entry_len..,
COMPACT_ZSET_COUNT_SIZE,
);
self.raw.truncate(self.raw.len() - entry_len);
let new_count = (self.len() - 1) as u16;
self.raw[0..COMPACT_ZSET_COUNT_SIZE].copy_from_slice(&new_count.to_be_bytes());
Some((member, score))
}
pub fn pop_max(&mut self) -> Option<(Vec<u8>, f64)> {
let count = self.len();
if count == 0 {
return None;
}
let last_offset =
CompactZSetCodec::collect_offsets(&self.raw, count, |offsets| offsets[count - 1]).ok()?;
let (_, entry) = CompactZSetCodec::parse_entry(&self.raw, last_offset).ok()?;
let member = entry.member.to_vec();
let score = entry.score;
self.raw.truncate(last_offset);
let new_count = (count - 1) as u16;
self.raw[0..2].copy_from_slice(&new_count.to_be_bytes());
Some((member, score))
}
pub fn zrange(&self, start: isize, stop: isize, rev: bool) -> Vec<(Vec<u8>, f64)> {
let len = self.len() as isize;
if len == 0 {
return Vec::new();
}
let actual_start = if start < 0 {
len.saturating_add(start).max(0)
} else {
start
};
let actual_stop = if stop < 0 {
len.saturating_add(stop)
} else {
stop
};
if actual_start >= len || actual_start > actual_stop {
return Vec::new();
}
let actual_start = actual_start as usize;
let actual_stop = (actual_stop.min(len - 1)) as usize;
let total_len = len as usize;
let mut items = Vec::with_capacity(actual_stop - actual_start + 1);
let _ = CompactZSetCodec::collect_offsets(&self.raw, total_len, |offsets| {
if rev {
let rev_start = total_len - 1 - actual_start;
let rev_stop = total_len - 1 - actual_stop;
for &offset in offsets[rev_stop..=rev_start].iter().rev() {
if let Ok((_, entry)) = CompactZSetCodec::parse_entry(&self.raw, offset) {
items.push((entry.member.to_vec(), entry.score));
}
}
} else {
for &offset in &offsets[actual_start..=actual_stop] {
if let Ok((_, entry)) = CompactZSetCodec::parse_entry(&self.raw, offset) {
items.push((entry.member.to_vec(), entry.score));
}
}
}
});
items
}
#[inline]
pub fn to_bitcode(&self) -> Vec<u8> {
bitcode::encode(&self.raw)
}
#[inline]
pub fn from_bitcode(bytes: &[u8]) -> Result<Self> {
let raw: Vec<u8> = bitcode::decode(bytes)?;
Self::from_vec(raw)
}
}
impl<'a> IntoIterator for &'a CompactZSet {
type Item = ZSetEntryRef<'a>;
type IntoIter = CompactZSetIter<'a>;
#[inline(always)]
fn into_iter(self) -> Self::IntoIter {
self.iter_members()
}
}
impl Deref for CompactZSet {
type Target = [u8];
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.raw
}
}
impl AsRef<[u8]> for CompactZSet {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
&self.raw
}
}