risingwave_storage/hummock/
value.rsuse std::fmt::Debug;
use bytes::{Buf, BufMut, Bytes};
use super::{HummockError, HummockResult};
pub const VALUE_DELETE: u8 = 1 << 0;
pub const VALUE_PUT: u8 = 0;
#[derive(Clone)]
pub enum HummockValue<T> {
Put(T),
Delete,
}
impl<T: AsRef<[u8]>> Debug for HummockValue<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
HummockValue::Put(v) => {
write!(f, "HummockValue {{ PUT, {} }}", hex::encode(v.as_ref()))
}
HummockValue::Delete => write!(f, "HummockValue {{ DELETE }}"),
}
}
}
impl<T> Copy for HummockValue<T> where T: Copy {}
#[cfg(any(test, feature = "test"))]
impl<T: PartialEq> PartialEq for HummockValue<T> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Put(l0), Self::Put(r0)) => l0.eq(r0),
(Self::Delete, Self::Delete) => true,
_ => false,
}
}
}
#[cfg(any(test, feature = "test"))]
impl<T: Eq> Eq for HummockValue<T> {}
impl<T> HummockValue<T>
where
T: AsRef<[u8]>,
{
pub fn encoded_len(&self) -> usize {
match self {
HummockValue::Put(val) => 1 + val.as_ref().len(),
HummockValue::Delete => 1,
}
}
pub fn encode(&self, buffer: &mut impl BufMut) {
match self {
HummockValue::Put(val) => {
buffer.put_u8(VALUE_PUT);
buffer.put_slice(val.as_ref());
}
HummockValue::Delete => {
buffer.put_u8(VALUE_DELETE);
}
}
}
pub fn into_user_value(self) -> Option<T> {
match self {
Self::Put(val) => Some(val),
Self::Delete => None,
}
}
pub fn is_delete(&self) -> bool {
matches!(self, Self::Delete)
}
pub fn put(data: T) -> Self {
Self::Put(data)
}
pub fn delete() -> Self {
Self::Delete
}
}
impl HummockValue<Vec<u8>> {
pub fn decode(buffer: &mut impl Buf) -> HummockResult<Self> {
if buffer.remaining() == 0 {
return Err(HummockError::decode_error("empty value"));
}
match buffer.get_u8() {
VALUE_PUT => Ok(Self::Put(Vec::from(buffer.chunk()))),
VALUE_DELETE => Ok(Self::Delete),
_ => Err(HummockError::decode_error("non-empty but format error")),
}
}
}
impl<B: AsRef<[u8]>> HummockValue<B> {
pub fn as_slice(&self) -> HummockValue<&[u8]> {
match self {
HummockValue::Put(data) => HummockValue::Put(data.as_ref()),
HummockValue::Delete => HummockValue::Delete,
}
}
}
impl<'a> HummockValue<&'a [u8]> {
pub fn from_slice(mut buffer: &'a [u8]) -> HummockResult<Self> {
if buffer.remaining() == 0 {
return Err(HummockError::decode_error("empty value"));
}
match buffer.get_u8() {
VALUE_PUT => Ok(Self::Put(buffer)),
VALUE_DELETE => Ok(Self::Delete),
_ => Err(HummockError::decode_error("non-empty but format error")),
}
}
pub fn to_bytes(self) -> HummockValue<Bytes> {
match self {
HummockValue::Put(value) => HummockValue::Put(Bytes::copy_from_slice(value)),
HummockValue::Delete => HummockValue::Delete,
}
}
}
impl HummockValue<Bytes> {
pub fn to_vec(&self) -> HummockValue<Vec<u8>> {
match self {
HummockValue::Put(data) => HummockValue::Put(data.to_vec()),
HummockValue::Delete => HummockValue::Delete,
}
}
}
impl From<HummockValue<Vec<u8>>> for HummockValue<Bytes> {
fn from(data: HummockValue<Vec<u8>>) -> Self {
match data {
HummockValue::Put(data) => HummockValue::Put(data.into()),
HummockValue::Delete => HummockValue::Delete,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vec_decode_encode() {
let mut result = vec![];
HummockValue::Put(b"233333".to_vec()).encode(&mut result);
assert_eq!(
HummockValue::Put(b"233333".to_vec()),
HummockValue::decode(&mut &result[..]).unwrap()
);
}
#[test]
fn test_slice_decode_encode() {
let mut result = vec![];
HummockValue::Put(b"233333".to_vec()).encode(&mut result);
assert_eq!(
HummockValue::Put(b"233333".as_slice()),
HummockValue::from_slice(&result).unwrap()
);
}
}