use wresp::{ArgSlice, SessionParseState};
use wval::GarnetObjectType;
use super::{
hash::hash_object::HashObject, list::list_object::ListObject, set::set_object::SetObject,
zset::sorted_set_object::SortedSetObject,
};
use crate::types::{ObjectInput, RespInputFlags, RespInputHeader};
pub fn make_object_input<T: AsRef<[u8]>>(
obj_type: GarnetObjectType,
sub_id: u8,
args: &[T],
arg1: i32,
arg2: i32,
) -> ObjectInput {
let slices: Vec<ArgSlice> = args
.iter()
.map(|a| {
let b = a.as_ref();
ArgSlice::new(b.as_ptr(), b.len())
})
.collect();
let mut parse_state = SessionParseState::new();
parse_state.initialize_with_args(&slices);
let mut header = RespInputHeader::new_with_type(obj_type, RespInputFlags::empty());
header.set_sub_id(sub_id);
ObjectInput {
header,
arg1,
arg2,
parse_state,
}
}
pub trait GarnetObjectPayload: Sized + Default {
const OBJECT_TAG: GarnetObjectType;
fn from_blob(raw: &[u8]) -> Self;
fn to_blob(&self) -> Vec<u8>;
fn is_empty(&self) -> bool;
}
#[inline]
pub fn obj_encode(tag: GarnetObjectType, payload: &[u8]) -> Vec<u8> {
obj_encode_custom(tag as u8, payload)
}
#[inline]
pub fn obj_encode_custom(tag: u8, payload: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(payload.len() + 1);
out.push(tag);
out.extend_from_slice(payload);
out
}
#[inline]
pub fn obj_decode(raw: &[u8], want: GarnetObjectType) -> Option<&[u8]> {
obj_decode_custom(raw, want as u8)
}
#[inline]
pub fn obj_decode_custom(raw: &[u8], want: u8) -> Option<&[u8]> {
raw
.split_first()
.filter(|(t, _)| **t == want)
.map(|(_, p)| p)
}
pub fn object_heap_estimate(raw: &[u8]) -> i64 {
let Some((&tag, payload)) = raw.split_first() else {
return 0;
};
match GarnetObjectType::from_u8(tag) {
Some(GarnetObjectType::SortedSet) => {
SortedSetObject::deserialize_from_slice(payload).map_or(0, |o| o.heap_memory_size)
}
Some(GarnetObjectType::List) => {
ListObject::deserialize_from_slice(payload).map_or(0, |o| o.heap_memory_size)
}
Some(GarnetObjectType::Hash) => {
HashObject::deserialize_from_slice(payload).map_or(0, |o| o.heap_memory_size)
}
Some(GarnetObjectType::Set) => {
SetObject::deserialize_from_slice(payload).map_or(0, |o| o.heap_memory_size)
}
_ => 0,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ObjLoad<T> {
Degrade,
WrongType,
Missing,
Present(T),
}
impl<T> ObjLoad<T> {
#[inline]
pub fn unwrap_or(self, fallback: T) -> T {
match self {
Self::Present(v) => v,
_ => fallback,
}
}
#[inline]
pub fn map<U>(self, f: impl FnOnce(T) -> U) -> ObjLoad<U> {
match self {
Self::Present(v) => ObjLoad::Present(f(v)),
Self::Degrade => ObjLoad::Degrade,
Self::WrongType => ObjLoad::WrongType,
Self::Missing => ObjLoad::Missing,
}
}
#[inline]
pub fn ok(self) -> Option<T> {
match self {
Self::Present(v) => Some(v),
_ => None,
}
}
#[inline]
pub fn as_ref(&self) -> ObjLoad<&T> {
match self {
Self::Present(v) => ObjLoad::Present(v),
Self::Degrade => ObjLoad::Degrade,
Self::WrongType => ObjLoad::WrongType,
Self::Missing => ObjLoad::Missing,
}
}
#[inline]
pub fn as_mut(&mut self) -> ObjLoad<&mut T> {
match self {
Self::Present(v) => ObjLoad::Present(v),
Self::Degrade => ObjLoad::Degrade,
Self::WrongType => ObjLoad::WrongType,
Self::Missing => ObjLoad::Missing,
}
}
#[inline]
pub fn unwrap_or_default(self) -> T
where
T: Default,
{
self.unwrap_or_else(T::default)
}
#[inline]
pub fn unwrap_or_else(self, f: impl FnOnce() -> T) -> T {
match self {
Self::Present(v) => v,
_ => f(),
}
}
#[inline]
pub const fn is_present(&self) -> bool {
matches!(self, Self::Present(_))
}
#[inline]
pub const fn is_degrade(&self) -> bool {
matches!(self, Self::Degrade)
}
#[inline]
pub const fn is_wrong_type(&self) -> bool {
matches!(self, Self::WrongType)
}
#[inline]
pub const fn is_missing(&self) -> bool {
matches!(self, Self::Missing)
}
}