use crate::raw_value_pointer::RawValuePointer;
use crate::value_enc::EncodedValue;
use crate::{
binary_uvarint, binary_uvarint_allocate, put_binary_uvariant_to_vec, EXPIRATION_OFFSET,
META_OFFSET, USER_META_OFFSET,
};
use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::string::{String, ToString};
use alloc::sync::Arc;
use alloc::vec::Vec;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use core::mem;
use core::slice::from_raw_parts;
const MAX_VALUE_INFO_SIZE: usize = mem::size_of::<u8>() * 2 + mem::size_of::<u64>();
#[derive(Default, Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Hash)]
#[repr(C)]
pub struct Value {
pub(crate) meta: u8,
pub(crate) user_meta: u8,
pub(crate) expires_at: u64,
pub(crate) version: u64, pub(crate) value: Bytes,
}
impl From<Value> for Bytes {
fn from(v: Value) -> Self {
let mut b = BytesMut::with_capacity(MAX_VALUE_INFO_SIZE + v.value.len());
b.put_u8(v.meta);
b.put_u8(v.user_meta);
b.put_u64(v.expires_at);
b.extend(v.value);
b.freeze()
}
}
impl Value {
#[inline]
pub const fn new() -> Self {
Self {
meta: 0,
user_meta: 0,
expires_at: 0,
version: 0,
value: Bytes::new(),
}
}
#[inline]
pub const fn with_all_fields(
meta: u8,
user_meta: u8,
expires_at: u64,
version: u64,
data: Bytes,
) -> Self {
Self {
meta,
user_meta,
expires_at,
version,
value: data,
}
}
#[inline]
pub fn decode_bytes(src: Bytes) -> Self {
let meta = src[META_OFFSET];
let user_meta = src[USER_META_OFFSET];
let (expires_at, sz) = binary_uvarint(&src[EXPIRATION_OFFSET..]);
let value = src.slice(EXPIRATION_OFFSET + sz..);
Self {
meta,
user_meta,
expires_at,
version: 0,
value,
}
}
#[inline]
pub const fn set_meta(mut self, meta: u8) -> Self {
self.meta = meta;
self
}
#[inline]
pub const fn set_user_meta(mut self, user_meta: u8) -> Self {
self.user_meta = user_meta;
self
}
#[inline]
pub const fn set_expires_at(mut self, expires_at: u64) -> Self {
self.expires_at = expires_at;
self
}
#[inline]
pub const fn set_version(mut self, version: u64) -> Self {
self.version = version;
self
}
#[inline]
pub fn set_data(mut self, value: Bytes) -> Self {
self.value = value;
self
}
#[inline]
pub const fn get_version(&self) -> u64 {
self.version
}
#[inline]
pub fn len(&self) -> usize {
self.value.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.value.is_empty()
}
}
impl ValueExt for Value {
#[inline]
fn as_value_ref(&self) -> ValueRef {
ValueRef {
meta: self.meta,
user_meta: self.user_meta,
expires_at: self.expires_at,
version: self.version,
val: self.parse_value(),
}
}
#[inline]
fn parse_value(&self) -> &[u8] {
self.value.as_ref()
}
#[inline]
fn parse_value_to_bytes(&self) -> Bytes {
self.value.clone()
}
#[inline]
fn get_meta(&self) -> u8 {
self.meta
}
#[inline]
fn get_user_meta(&self) -> u8 {
self.user_meta
}
#[inline]
fn get_expires_at(&self) -> u64 {
self.expires_at
}
impl_psfix_suites!(ValueExt::parse_value, u8, "u8");
}
fn size_variant(mut x: u64) -> usize {
let mut n = 0;
loop {
n += 1;
x >>= 7;
if x == 0 {
break;
}
}
n
}
macro_rules! impl_from_for_value {
($($ty: ty), +$(,)?) => {
$(
impl From<$ty> for Value {
fn from(val: $ty) -> Self {
Self {
meta: 0,
user_meta: 0,
expires_at: 0,
value: Bytes::from(val),
version: 0,
}
}
}
)*
};
}
impl_from_for_value! {
String,
&'static str,
&'static [u8],
Vec<u8>,
Box<[u8]>,
Bytes,
BytesMut,
}
pub trait ValueExt {
#[inline]
fn as_value_ref(&self) -> ValueRef {
ValueRef {
meta: self.get_meta(),
user_meta: self.get_user_meta(),
expires_at: self.get_expires_at(),
version: 0,
val: self.parse_value(),
}
}
fn parse_value(&self) -> &[u8];
fn parse_value_to_bytes(&self) -> Bytes;
fn get_meta(&self) -> u8;
fn get_user_meta(&self) -> u8;
fn get_expires_at(&self) -> u64;
#[inline]
fn encoded_size(&self) -> u32 {
let sz = self.parse_value().len() + 2; let enc = size_variant(self.get_expires_at());
(sz + enc) as u32
}
fn encode(&self, mut buf: &mut [u8]) {
buf.put_u8(self.get_meta());
buf.put_u8(self.get_user_meta());
buf.put_slice(binary_uvarint_allocate(self.get_expires_at()).as_slice());
buf.put_slice(self.parse_value());
}
fn encode_to_buf(&self, mut buf: impl BufMut) {
buf.put_u8(self.get_meta());
buf.put_u8(self.get_user_meta());
buf.put_slice(binary_uvarint_allocate(self.get_expires_at()).as_slice());
buf.put_slice(self.parse_value());
}
#[inline]
fn to_encoded(&self) -> EncodedValue {
let mut data = Vec::with_capacity(MAX_VALUE_INFO_SIZE);
data.push(self.get_meta());
data.push(self.get_user_meta());
put_binary_uvariant_to_vec(data.as_mut(), self.get_expires_at());
let expires_sz = data.len() - 2;
let meta = Bytes::from(data);
let val = self.parse_value_to_bytes();
let enc_len = meta.len() + val.len();
EncodedValue {
data: meta.chain(val).copy_to_bytes(enc_len),
expires_sz: expires_sz as u8,
}
}
#[inline]
fn decode_value_ref(src: &[u8]) -> ValueRef {
let meta = src[META_OFFSET];
let user_meta = src[USER_META_OFFSET];
let (expires_at, sz) = binary_uvarint(&src[EXPIRATION_OFFSET..]);
ValueRef {
meta,
user_meta,
expires_at,
version: 0,
val: &src[EXPIRATION_OFFSET + sz..],
}
}
#[inline]
fn decode_value(src: &[u8]) -> Value {
let meta = src[META_OFFSET];
let user_meta = src[USER_META_OFFSET];
let (expires_at, sz) = binary_uvarint(&src[EXPIRATION_OFFSET..]);
let value = src[EXPIRATION_OFFSET + sz..].to_vec().into();
Value {
meta,
user_meta,
expires_at,
version: 0,
value,
}
}
#[inline]
fn decode_bytes(src: Bytes) -> Value {
let meta = src[META_OFFSET];
let user_meta = src[USER_META_OFFSET];
let (expires_at, sz) = binary_uvarint(&src[EXPIRATION_OFFSET..]);
let value = src.slice(EXPIRATION_OFFSET + sz..);
Value {
meta,
user_meta,
expires_at,
version: 0,
value,
}
}
impl_psfix_suites!(ValueExt::parse_value, u8, "u8");
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ValueRef<'a> {
pub(crate) meta: u8,
pub(crate) user_meta: u8,
pub(crate) expires_at: u64,
pub(crate) version: u64, pub(crate) val: &'a [u8],
}
impl<'a> ValueRef<'a> {
#[inline]
pub const fn new(
meta: u8,
user_meta: u8,
expires_at: u64,
version: u64,
data: &'a [u8],
) -> Self {
Self {
meta,
user_meta,
expires_at,
version,
val: data,
}
}
#[inline]
pub unsafe fn from_raw_value_pointer(rp: RawValuePointer) -> ValueRef<'a> {
ValueRef {
meta: rp.meta,
user_meta: rp.user_meta,
expires_at: rp.expires_at,
version: rp.version,
val: from_raw_parts(rp.ptr, rp.l as usize),
}
}
#[inline]
#[allow(clippy::inherent_to_string)]
pub fn to_string(&self) -> String {
String::from_utf8_lossy(self.val).to_string()
}
#[inline]
pub fn to_lossy_string(&self) -> Cow<'_, str> {
String::from_utf8_lossy(self.val)
}
#[inline]
pub fn to_value(&self) -> Value {
Value {
meta: self.meta,
user_meta: self.user_meta,
expires_at: self.expires_at,
version: self.version,
value: Bytes::copy_from_slice(self.val),
}
}
#[inline]
pub fn get_version(&self) -> u64 {
self.version
}
#[inline]
pub fn set_version(&mut self, version: u64) {
self.version = version
}
}
impl<'a> ValueExt for ValueRef<'a> {
#[inline]
fn as_value_ref(&self) -> ValueRef {
*self
}
#[inline]
fn parse_value(&self) -> &[u8] {
self.val
}
#[inline]
fn parse_value_to_bytes(&self) -> Bytes {
Bytes::copy_from_slice(self.val)
}
#[inline]
fn get_meta(&self) -> u8 {
self.meta
}
#[inline]
fn get_user_meta(&self) -> u8 {
self.user_meta
}
#[inline]
fn get_expires_at(&self) -> u64 {
self.expires_at
}
}
impl<const N: usize> ValueExt for [u8; N] {
fn parse_value(&self) -> &[u8] {
self
}
fn parse_value_to_bytes(&self) -> Bytes {
Bytes::copy_from_slice(self)
}
fn get_meta(&self) -> u8 {
self[META_OFFSET]
}
fn get_user_meta(&self) -> u8 {
self[USER_META_OFFSET]
}
fn get_expires_at(&self) -> u64 {
let (expires_at, _) = binary_uvarint(&self[EXPIRATION_OFFSET..]);
expires_at
}
}
impl<'a> ValueExt for &'a [u8] {
fn parse_value(&self) -> &[u8] {
self
}
fn parse_value_to_bytes(&self) -> Bytes {
Bytes::copy_from_slice(self)
}
fn get_meta(&self) -> u8 {
self[META_OFFSET]
}
fn get_user_meta(&self) -> u8 {
self[USER_META_OFFSET]
}
fn get_expires_at(&self) -> u64 {
let (expires_at, _) = binary_uvarint(&self[EXPIRATION_OFFSET..]);
expires_at
}
}
impl ValueExt for Box<[u8]> {
fn parse_value(&self) -> &[u8] {
self
}
fn parse_value_to_bytes(&self) -> Bytes {
Bytes::copy_from_slice(self)
}
fn get_meta(&self) -> u8 {
self[META_OFFSET]
}
fn get_user_meta(&self) -> u8 {
self[USER_META_OFFSET]
}
fn get_expires_at(&self) -> u64 {
let (expires_at, _) = binary_uvarint(&self[EXPIRATION_OFFSET..]);
expires_at
}
}
impl ValueExt for Arc<[u8]> {
fn parse_value(&self) -> &[u8] {
self
}
fn parse_value_to_bytes(&self) -> Bytes {
Bytes::copy_from_slice(self)
}
fn get_meta(&self) -> u8 {
self[META_OFFSET]
}
fn get_user_meta(&self) -> u8 {
self[USER_META_OFFSET]
}
fn get_expires_at(&self) -> u64 {
let (expires_at, _) = binary_uvarint(&self[EXPIRATION_OFFSET..]);
expires_at
}
}
impl ValueExt for Rc<[u8]> {
fn parse_value(&self) -> &[u8] {
self
}
fn parse_value_to_bytes(&self) -> Bytes {
Bytes::copy_from_slice(self)
}
fn get_meta(&self) -> u8 {
self[META_OFFSET]
}
fn get_user_meta(&self) -> u8 {
self[USER_META_OFFSET]
}
fn get_expires_at(&self) -> u64 {
let (expires_at, _) = binary_uvarint(&self[EXPIRATION_OFFSET..]);
expires_at
}
}