use crate::{
bftag::BfTag,
error::{Error, Result},
header::{HEADER_SIZE, RecordHeader},
meta::{MetaValue, SubKeyRef},
simd::fast_key_eq,
tag::KeyTag,
zset::{ZMemberKeyRef, ZScoreKeyRef, ZSetSubKeyCodec},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RecordRef<'a> {
pub header: RecordHeader,
pub key: &'a [u8],
pub value: &'a [u8],
}
impl<'a> RecordRef<'a> {
#[inline]
pub const fn from_slice(slice: &'a [u8]) -> Result<Self> {
let header = match RecordHeader::from_slice(slice) {
Ok(h) => h,
Err(e) => return Err(e),
};
let key_len = header.key_len as usize;
let total_size = match header.checked_record_size() {
Some(s) => s,
None => return Err(Error::RecordSizeOverflow),
};
if slice.len() < total_size {
return Err(Error::BufferTooShort {
expected: total_size,
actual: slice.len(),
});
}
let (_, after_hdr) = slice.split_at(HEADER_SIZE);
let (key, after_key) = after_hdr.split_at(key_len);
let (value, _) = after_key.split_at(header.val_len as usize);
Ok(Self { header, key, value })
}
#[inline]
pub const fn split_from_slice(slice: &'a [u8]) -> Result<(Self, &'a [u8])> {
let rec = match Self::from_slice(slice) {
Ok(r) => r,
Err(e) => return Err(e),
};
let phys_size = match rec.header.checked_physical_size() {
Some(s) => s,
None => return Err(Error::RecordSizeOverflow),
};
if slice.len() < phys_size {
return Err(Error::BufferTooShort {
expected: phys_size,
actual: slice.len(),
});
}
let (_, remaining) = slice.split_at(phys_size);
Ok((rec, remaining))
}
#[inline(always)]
pub const fn filler_words(&self) -> u8 {
self.header.filler_words()
}
#[inline(always)]
pub const fn filler_rem(&self) -> u8 {
self.header.filler_rem()
}
#[inline(always)]
pub const fn filler_bytes(&self) -> usize {
self.header.filler_bytes()
}
#[inline(always)]
pub const fn val_capacity(&self) -> usize {
self.header.val_capacity()
}
#[inline(always)]
pub const fn physical_size(&self) -> usize {
self.header.physical_size()
}
#[inline]
pub const fn header(&self) -> &RecordHeader {
&self.header
}
#[inline]
pub const fn key(&self) -> &'a [u8] {
self.key
}
#[inline(always)]
pub const fn tag(&self) -> Option<KeyTag> {
if let [first, ..] = self.key {
KeyTag::from_repr(*first)
} else {
None
}
}
#[inline(always)]
pub const fn bftag(&self) -> Option<BfTag> {
if let [first, ..] = self.key {
BfTag::from_repr(*first)
} else {
None
}
}
#[inline]
pub fn matches_key(&self, target_key: &[u8]) -> bool {
fast_key_eq(self.key, target_key)
}
#[inline]
pub const fn value(&self) -> &'a [u8] {
self.value
}
#[inline]
pub const fn prev_address(&self) -> u64 {
self.header.address()
}
#[inline(always)]
pub const fn is_tombstone(&self) -> bool {
self.header.is_tombstone()
}
#[inline(always)]
pub const fn is_modified(&self) -> bool {
self.header.is_modified()
}
#[inline(always)]
pub const fn is_sealed(&self) -> bool {
self.header.is_sealed()
}
#[inline(always)]
pub const fn is_in_new_version(&self) -> bool {
self.header.is_in_new_version()
}
#[inline(always)]
pub const fn is_read_cache(&self) -> bool {
self.header.is_read_cache()
}
#[inline(always)]
pub const fn can_update_in_place(&self, new_val_len: usize) -> bool {
self.header.can_update_in_place(new_val_len)
}
#[inline]
pub const fn key_len(&self) -> u32 {
self.header.key_len
}
#[inline]
pub const fn val_len(&self) -> u32 {
self.header.val_len
}
#[inline]
pub const fn total_size(&self) -> usize {
self.header.record_size()
}
#[inline]
pub const fn meta_value(&self) -> Result<MetaValue> {
MetaValue::from_slice(self.value)
}
#[inline]
pub const fn sub_key_ref(&self) -> Result<SubKeyRef<'a>> {
SubKeyRef::from_slice(self.key)
}
#[inline(always)]
pub const fn zmember_key_ref(&self) -> Result<ZMemberKeyRef<'a>> {
ZSetSubKeyCodec::decode_member_key(self.key)
}
#[inline(always)]
pub const fn zscore_key_ref(&self) -> Result<ZScoreKeyRef<'a>> {
ZSetSubKeyCodec::decode_score_key(self.key)
}
}