use core::fmt;
use core::hash::{Hash, Hasher};
use core::mem::MaybeUninit;
use core::ops::Deref;
use core::ptr;
use core::slice;
use crate::CapacityError;
pub struct FixedBlob<const N: usize> {
data: [MaybeUninit<u8>; N],
init: usize,
}
impl<const N: usize> FixedBlob<N> {
pub const fn new() -> Self {
Self {
data: unsafe { MaybeUninit::<[MaybeUninit<u8>; N]>::uninit().assume_init() },
init: 0,
}
}
pub const fn from_array(data: [u8; N]) -> Self {
Self {
data: unsafe { ptr::read(data.as_ptr().cast()) },
init: N,
}
}
pub(super) fn as_mut_ptr(&mut self) -> *mut u8 {
self.data.as_mut_ptr().cast()
}
pub(super) unsafe fn set_len(&mut self, len: usize) {
self.init = len;
}
pub fn into_bytes(self) -> Result<[u8; N], Self> {
if self.init != N {
return Err(self);
}
unsafe { Ok((&self.data as *const _ as *const [u8; N]).read()) }
}
pub fn as_slice(&self) -> &[u8] {
if self.init == 0 {
return &[];
}
unsafe { slice::from_raw_parts(self.data.as_ptr() as *const u8, self.init) }
}
}
impl<const N: usize> Deref for FixedBlob<N> {
type Target = [u8];
#[inline]
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl<const N: usize> fmt::Debug for FixedBlob<N> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.as_slice().fmt(f)
}
}
impl<const N: usize> AsRef<[u8]> for FixedBlob<N> {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl<const N: usize> PartialEq for FixedBlob<N> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<const N: usize> Eq for FixedBlob<N> {}
impl<const N: usize> PartialOrd for FixedBlob<N> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<const N: usize> Ord for FixedBlob<N> {
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.as_slice().cmp(other.as_slice())
}
}
impl<const N: usize> Hash for FixedBlob<N> {
#[inline]
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.as_slice().hash(state)
}
}
impl<const N: usize> Clone for FixedBlob<N> {
#[inline]
fn clone(&self) -> Self {
Self {
init: self.init,
data: self.data,
}
}
}
impl<const N: usize> From<[u8; N]> for FixedBlob<N> {
#[inline]
fn from(value: [u8; N]) -> Self {
Self::from_array(value)
}
}
impl<const N: usize> From<&[u8; N]> for FixedBlob<N> {
#[inline]
fn from(value: &[u8; N]) -> Self {
Self::from_array(*value)
}
}
impl<const N: usize> TryFrom<&[u8]> for FixedBlob<N> {
type Error = CapacityError;
#[inline]
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
unsafe {
let mut blob = FixedBlob::<N>::new();
if value.len() > N {
return Err(CapacityError::capacity(value.len(), N));
}
ptr::copy_nonoverlapping(value.as_ptr(), blob.as_mut_ptr(), value.len());
blob.set_len(value.len());
Ok(blob)
}
}
}