use crate::queue::ByteCost;
use alloc::sync::Arc;
use core::{fmt, mem::MaybeUninit, ops::Deref, ptr};
#[derive(Clone)]
pub enum SmallPayload<const INLINE: usize> {
Inline { len: u8, buf: InlineBuf<INLINE> },
Heap(Arc<[u8]>),
}
#[derive(Clone)]
pub struct InlineBuf<const N: usize> {
buf: [MaybeUninit<u8>; N],
}
impl<const N: usize> InlineBuf<N> {
#[inline]
pub fn from_slice(data: &[u8]) -> (Self, u8) {
assert!(
data.len() <= N,
"InlineBuf capacity exceeded: data.len()={}, capacity={}",
data.len(),
N
);
assert!(
data.len() <= u8::MAX as usize,
"InlineBuf len does not fit in u8: {}",
data.len()
);
let mut buf: [MaybeUninit<u8>; N] = unsafe { MaybeUninit::uninit().assume_init() };
if !data.is_empty() {
unsafe {
ptr::copy_nonoverlapping(data.as_ptr(), buf.as_mut_ptr() as *mut u8, data.len());
}
}
(InlineBuf { buf }, data.len() as u8)
}
#[inline]
pub fn as_slice(&self, len: u8) -> &[u8] {
let len = len as usize;
unsafe { core::slice::from_raw_parts(self.buf.as_ptr() as *const u8, len) }
}
}
impl<const INLINE: usize> SmallPayload<INLINE> {
#[inline]
pub fn new(data: &[u8]) -> Self {
if data.len() <= INLINE {
let (buf, len) = InlineBuf::<INLINE>::from_slice(data);
Self::Inline { len, buf }
} else {
Self::Heap(Arc::from(data))
}
}
#[inline]
fn byte_cost(&self) -> usize {
match self {
SmallPayload::Inline { len, .. } => *len as usize,
SmallPayload::Heap(a) => a.len() + size_of::<Arc<[u8]>>(),
}
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
match self {
SmallPayload::Inline { len, buf } => buf.as_slice(*len),
SmallPayload::Heap(arc) => arc,
}
}
#[inline]
#[allow(dead_code)]
pub fn to_arc(&self) -> Arc<[u8]> {
match self {
SmallPayload::Inline { len, buf } => {
Arc::from(buf.as_slice(*len))
}
SmallPayload::Heap(arc) => arc.clone(),
}
}
#[inline]
pub fn len(&self) -> usize {
match self {
SmallPayload::Inline { len, .. } => *len as usize,
SmallPayload::Heap(a) => a.len(),
}
}
#[inline]
#[allow(dead_code)]
pub fn is_inline(&self) -> bool {
matches!(self, SmallPayload::Inline { .. })
}
}
impl<const INLINE: usize> fmt::Debug for SmallPayload<INLINE> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Inline { len, .. } => {
write!(f, "SmallPayload::Inline({} bytes)", len)
}
Self::Heap(a) => {
write!(f, "SmallPayload::Heap({} bytes)", a.len())
}
}
}
}
impl<const INLINE: usize> Deref for SmallPayload<INLINE> {
type Target = [u8];
#[inline]
fn deref(&self) -> &[u8] {
self.as_slice()
}
}
impl<const INLINE: usize> PartialEq for SmallPayload<INLINE> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<const INLINE: usize> Eq for SmallPayload<INLINE> {}
impl<const INLINE: usize> PartialEq<[u8]> for SmallPayload<INLINE> {
#[inline]
fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other
}
}
impl<const INLINE: usize> PartialEq<SmallPayload<INLINE>> for [u8] {
#[inline]
fn eq(&self, other: &SmallPayload<INLINE>) -> bool {
self == other.as_slice()
}
}
impl<const INLINE: usize> PartialEq<Arc<[u8]>> for SmallPayload<INLINE> {
#[inline]
fn eq(&self, other: &Arc<[u8]>) -> bool {
self.as_slice() == other.as_ref()
}
}
impl<const INLINE: usize> ByteCost for SmallPayload<INLINE> {
#[inline]
fn byte_cost(&self) -> usize {
self.byte_cost()
}
}