use crate::{byte2hex, imp};
use core::fmt;
use core::slice;
use core::str;
#[cfg(feature = "alloc")]
#[allow(unused_imports)]
use alloc::{string::String, vec::Vec};
#[must_use]
#[repr(C)]
#[derive(Clone)]
pub struct Buffer<const N: usize, const PREFIX: bool = false> {
prefix: [u8; 2],
bytes: [[u8; 2]; N],
}
impl<const N: usize, const PREFIX: bool> Default for Buffer<N, PREFIX> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<const N: usize, const PREFIX: bool> fmt::Debug for Buffer<N, PREFIX> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Buffer").field(&self.as_str()).finish()
}
}
impl<const N: usize, const PREFIX: bool> AsRef<str> for Buffer<N, PREFIX> {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<const N: usize, const PREFIX: bool> Buffer<N, PREFIX> {
pub const LEN: usize = (N + PREFIX as usize) * 2;
const ASSERT_SIZE: () = assert!(core::mem::size_of::<Self>() == 2 + N * 2, "invalid size");
const ASSERT_ALIGNMENT: () = assert!(core::mem::align_of::<Self>() == 1, "invalid alignment");
#[inline]
pub const fn new() -> Self {
let () = Self::ASSERT_SIZE;
let () = Self::ASSERT_ALIGNMENT;
Self {
prefix: if PREFIX { [b'0', b'x'] } else { [0, 0] },
bytes: [[0; 2]; N],
}
}
#[inline]
pub const fn const_format(self, array: &[u8; N]) -> Self {
self.const_format_inner::<false>(array)
}
#[inline]
pub const fn const_format_upper(self, array: &[u8; N]) -> Self {
self.const_format_inner::<true>(array)
}
const fn const_format_inner<const UPPER: bool>(mut self, array: &[u8; N]) -> Self {
let mut i = 0;
while i < N {
let (high, low) = byte2hex::<UPPER>(array[i]);
self.bytes[i][0] = high;
self.bytes[i][1] = low;
i += 1;
}
self
}
#[inline]
pub fn format(&mut self, array: &[u8; N]) -> &mut str {
self.format_inner::<false>(array)
}
#[inline]
pub fn format_upper(&mut self, array: &[u8; N]) -> &mut str {
self.format_inner::<true>(array)
}
#[track_caller]
#[inline]
pub fn format_slice<T: AsRef<[u8]>>(&mut self, slice: T) -> &mut str {
self.format_slice_inner::<false>(slice.as_ref())
}
#[track_caller]
#[inline]
pub fn format_slice_upper<T: AsRef<[u8]>>(&mut self, slice: T) -> &mut str {
self.format_slice_inner::<true>(slice.as_ref())
}
#[track_caller]
fn format_slice_inner<const UPPER: bool>(&mut self, slice: &[u8]) -> &mut str {
assert_eq!(slice.len(), N, "length mismatch");
self.format_inner::<UPPER>(slice)
}
#[inline]
fn format_inner<const UPPER: bool>(&mut self, input: &[u8]) -> &mut str {
unsafe {
let buf = self.as_mut_bytes();
let output = buf.get_unchecked_mut(PREFIX as usize * 2..);
imp::encode::<UPPER>(input, output);
str::from_utf8_unchecked_mut(buf)
}
}
#[cfg(feature = "alloc")]
#[inline]
#[allow(clippy::inherent_to_string)] pub fn to_string(&self) -> String {
unsafe { String::from_utf8_unchecked(self.as_bytes().to_vec()) }
}
#[inline]
pub const fn as_str(&self) -> &str {
unsafe { str::from_utf8_unchecked(self.as_bytes()) }
}
#[inline]
pub fn as_mut_str(&mut self) -> &mut str {
unsafe { str::from_utf8_unchecked_mut(self.as_mut_bytes()) }
}
#[cfg(feature = "alloc")]
#[inline]
pub fn to_vec(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}
#[inline]
pub const fn as_byte_array<const LEN: usize>(&self) -> &[u8; LEN] {
maybe_const_assert!(LEN == Self::LEN, "`LEN` must be equal to `Self::LEN`");
unsafe { &*self.as_ptr().cast::<[u8; LEN]>() }
}
#[inline]
pub fn as_mut_byte_array<const LEN: usize>(&mut self) -> &mut [u8; LEN] {
maybe_const_assert!(LEN == Self::LEN, "`LEN` must be equal to `Self::LEN`");
unsafe { &mut *self.as_mut_ptr().cast::<[u8; LEN]>() }
}
#[inline]
pub const fn as_bytes(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.as_ptr(), Self::LEN) }
}
#[inline]
pub unsafe fn as_mut_bytes(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), Self::LEN) }
}
#[inline]
pub unsafe fn buffer(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.bytes.as_mut_ptr().cast(), N * 2) }
}
#[inline]
pub const fn as_ptr(&self) -> *const u8 {
unsafe { (self as *const Self).cast::<u8>().add(!PREFIX as usize * 2) }
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut u8 {
unsafe { (self as *mut Self).cast::<u8>().add(!PREFIX as usize * 2) }
}
}