use core::{
borrow::Borrow,
cmp::Ordering,
hash::{Hash, Hasher},
ops::Deref,
};
#[cfg(feature = "simd")]
use crate::simd::fast_key_eq;
#[inline(always)]
fn slice_eq(a: &[u8], b: &[u8]) -> bool {
#[cfg(feature = "simd")]
{
fast_key_eq(a, b)
}
#[cfg(not(feature = "simd"))]
{
a == b
}
}
#[derive(Debug, Clone)]
pub enum StackHeapBuf<const CAP: usize> {
#[non_exhaustive]
Stack([u8; CAP], u8),
#[non_exhaustive]
Heap(Vec<u8>),
}
impl<const CAP: usize> StackHeapBuf<CAP> {
#[inline(always)]
const fn assert_cap() {
const { assert!(CAP <= 255, "StackHeapBuf 栈容量不得超过 255 字节") }
}
#[inline(always)]
pub const fn from_stack(buf: [u8; CAP], len: u8) -> Self {
Self::assert_cap();
Self::Stack(buf, len)
}
#[inline(always)]
pub const fn from_heap(vec: Vec<u8>) -> Self {
Self::assert_cap();
Self::Heap(vec)
}
#[inline(always)]
pub fn as_slice(&self) -> &[u8] {
self
}
#[inline(always)]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
match self {
Self::Stack(buf, len) => {
let len = (*len as usize).min(CAP);
unsafe { buf.get_unchecked_mut(..len) }
}
Self::Heap(vec) => vec.as_mut_slice(),
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.as_slice().len()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline(always)]
pub const fn is_stack(&self) -> bool {
matches!(self, Self::Stack(..))
}
#[inline(always)]
pub const fn is_heap(&self) -> bool {
matches!(self, Self::Heap(..))
}
#[inline]
pub fn into_vec(self) -> Vec<u8> {
match self {
Self::Stack(buf, len) => {
let len = (len as usize).min(CAP);
unsafe { buf.get_unchecked(..len) }.to_vec()
}
Self::Heap(vec) => vec,
}
}
}
impl<const CAP: usize> Deref for StackHeapBuf<CAP> {
type Target = [u8];
#[inline(always)]
fn deref(&self) -> &Self::Target {
match self {
Self::Stack(buf, len) => {
let len = (*len as usize).min(CAP);
unsafe { buf.get_unchecked(..len) }
}
Self::Heap(vec) => vec.as_slice(),
}
}
}
impl<const CAP: usize> AsRef<[u8]> for StackHeapBuf<CAP> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl<const CAP: usize> Borrow<[u8]> for StackHeapBuf<CAP> {
#[inline(always)]
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}
impl<const CAP: usize> PartialEq for StackHeapBuf<CAP> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
slice_eq(self.as_slice(), other.as_slice())
}
}
impl<const CAP: usize> Eq for StackHeapBuf<CAP> {}
impl<const CAP: usize> PartialOrd for StackHeapBuf<CAP> {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<const CAP: usize> Ord for StackHeapBuf<CAP> {
#[inline(always)]
fn cmp(&self, other: &Self) -> Ordering {
self.as_slice().cmp(other.as_slice())
}
}
impl<const CAP: usize> Hash for StackHeapBuf<CAP> {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_slice().hash(state);
}
}
impl<const CAP: usize> From<Vec<u8>> for StackHeapBuf<CAP> {
#[inline]
fn from(vec: Vec<u8>) -> Self {
Self::assert_cap();
if vec.len() <= CAP {
let mut buf = [0u8; CAP];
buf[..vec.len()].copy_from_slice(&vec);
Self::Stack(buf, vec.len() as u8)
} else {
Self::Heap(vec)
}
}
}
impl<const CAP: usize> From<&[u8]> for StackHeapBuf<CAP> {
#[inline]
fn from(slice: &[u8]) -> Self {
Self::assert_cap();
if slice.len() <= CAP {
let mut buf = [0u8; CAP];
buf[..slice.len()].copy_from_slice(slice);
Self::Stack(buf, slice.len() as u8)
} else {
Self::Heap(slice.to_vec())
}
}
}