pub mod size;
use crate::buf::size::ConstByteBufSize;
use core::fmt::Debug;
use core::fmt::Display;
use core::hash::Hash;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
pub type ConstStrBuf<const CAP: usize> = ConstByteBuf<CAP, Utf8SafeBuf>;
pub struct ConstByteBuf<const CAP: usize, TData = DefBuf>
where
TData: ConstByteBufData,
{
tdata: PhantomData<TData>,
buf: [MaybeUninit<u8>; CAP],
wpos: usize,
}
pub trait ConstByteBufData {}
pub enum Utf8SafeBuf {}
impl ConstByteBufData for Utf8SafeBuf {}
pub enum DefBuf {}
impl ConstByteBufData for DefBuf {}
impl<const CAP: usize, TData: ConstByteBufData> ConstByteBuf<CAP, TData> {
#[inline]
pub const fn new() -> Self {
Self {
tdata: PhantomData,
buf: [MaybeUninit::uninit(); CAP],
wpos: 0,
}
}
#[inline]
pub const fn clone(&self) -> Self {
Self {
tdata: PhantomData,
buf: self.buf,
wpos: self.wpos,
}
}
const fn _pop(&mut self) -> Option<u8> {
match self.wpos {
0 => None,
pos => {
let result = core::mem::replace(&mut self.buf[pos], MaybeUninit::uninit());
self.wpos -= 1;
Some(unsafe { result.assume_init() })
}
}
}
#[cfg_attr(docsrs, doc(cfg(feature = "clufulltransmute")))]
#[cfg(feature = "clufulltransmute")]
const fn _into_array(mut self, space: u8) -> (usize, [u8; CAP]) {
let len = self.len();
while self.__try_write_byte(space).is_ok() {}
(len, unsafe {
cluFullTransmute::transmute_unchecked(self.buf as [MaybeUninit<u8>; CAP])
})
}
#[inline]
pub const fn clear(&mut self) {
self.wpos = 0;
}
#[inline]
pub const fn capacity(&self) -> usize {
self.buf.len()
}
const fn _get_mut(&mut self, pos: usize) -> Option<&mut u8> {
if pos > self.wpos {
return None;
}
unsafe { Some(self.buf[pos].assume_init_mut()) }
}
pub const fn get(&self, pos: usize) -> Option<&u8> {
if pos > self.wpos {
return None;
}
unsafe { Some(self.buf[pos].assume_init_ref()) }
}
#[inline]
pub const fn len(&self) -> usize {
self.wpos
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.wpos == 0
}
#[inline]
pub const fn available(&self) -> usize {
CAP - self.wpos
}
#[inline]
pub const fn as_ptr(&self) -> *const MaybeUninit<u8> {
self.buf.as_ptr()
}
#[inline]
pub const fn as_mut_ptr(&mut self) -> *mut MaybeUninit<u8> {
self.buf.as_mut_ptr()
}
#[inline]
pub const fn as_bytes(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.as_ptr() as *const u8, self.wpos) }
}
#[inline]
const fn _as_mut_bytes(&mut self) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr() as *mut u8, self.wpos) }
}
#[inline]
pub const fn push_str(&mut self, s: &str) -> usize {
self.__write_bytes_unchecked(s.as_bytes())
}
#[inline]
pub const fn try_push_str(&mut self, s: &str) -> Result<usize, StackOverflow> {
self.__try_write_bytes_unchecked(s.as_bytes())
}
#[track_caller]
#[inline]
const fn __write_bytes_unchecked(&mut self, data: &[u8]) -> usize {
match self.__try_write_bytes_unchecked(data) {
Ok(a) => a,
Err(_) => Self::cold_overflow_panic(),
}
}
const fn __try_write_bytes_unchecked(&mut self, data: &[u8]) -> Result<usize, StackOverflow> {
let datalen = data.len();
if self.wpos + datalen > CAP {
return Err(StackOverflow);
}
let mut i = 0;
while i < datalen {
self.buf[self.wpos + i].write(data[i]);
i += 1;
}
self.wpos += datalen;
Ok(datalen)
}
const fn __write_byte(&mut self, data: u8) -> usize {
match self.__try_write_byte(data) {
Ok(a) => a,
Err(_) => Self::cold_overflow_panic(),
}
}
const fn __try_write_byte(&mut self, data: u8) -> Result<usize, StackOverflow> {
let datalen = 1;
if self.wpos + datalen > CAP {
return Err(StackOverflow);
}
self.buf[self.wpos].write(data);
self.wpos += datalen;
Ok(datalen)
}
pub const fn push_char(&mut self, value: char) -> usize {
match self.try_push_char(value) {
Ok(a) => a,
Err(_) => Self::cold_overflow_panic(),
}
}
pub const fn try_push_char(&mut self, value: char) -> Result<usize, StackOverflow> {
let mut buf: [u8; <char as ConstByteBufSize>::MAX_DECIMAL_LEN] =
unsafe { core::mem::zeroed() };
let str = value.encode_utf8(&mut buf);
self.try_push_str(str)
}
pub const fn push_usize(&mut self, value: usize) -> usize {
match self.try_push_usize(value) {
Ok(a) => a,
Err(_) => Self::cold_overflow_panic(),
}
}
pub const fn try_push_usize(&mut self, mut value: usize) -> Result<usize, StackOverflow> {
let mut arr: [MaybeUninit<u8>; usize::MAX_DECIMAL_LEN] =
[MaybeUninit::uninit(); usize::MAX_DECIMAL_LEN];
let arr_len = arr.len();
let mut len;
if value == 0 {
arr[arr_len - 1].write(b'0');
len = 1;
} else {
len = 0;
let mut i = arr_len;
while value != 0 {
i -= 1;
arr[i].write(b'0' + (value % 10) as u8);
value /= 10;
len += 1;
}
}
let start = arr_len - len;
let dataptr = unsafe { arr.as_ptr().add(start) };
let slice = unsafe { core::slice::from_raw_parts(dataptr as *const u8, len) };
self.__try_write_bytes_unchecked(slice)
}
pub const fn push_isize(&mut self, value: isize) -> usize {
match self.try_push_isize(value) {
Ok(a) => a,
Err(_) => Self::cold_overflow_panic(),
}
}
pub const fn try_push_isize(&mut self, value: isize) -> Result<usize, StackOverflow> {
let abs: usize = match value < 0 {
true => {
if let Err(e) = self.__try_write_byte(b'-') {
return Err(e);
}
value.wrapping_neg() as usize
}
false => value as usize,
};
self.try_push_usize(abs)
}
#[cold]
#[track_caller]
#[inline(never)]
const fn cold_overflow_panic() -> ! {
panic!("ConstByteBuf overflow: capacity exceeded");
}
}
impl<const CAP: usize> ConstByteBuf<CAP, Utf8SafeBuf> {
#[inline]
pub const fn as_str(&self) -> &str {
unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
}
#[inline]
pub const fn as_mut_str(&mut self) -> &mut str {
unsafe { core::str::from_utf8_unchecked_mut(self.as_mut_bytes()) }
}
#[track_caller]
#[inline]
pub const unsafe fn write_bytes_unchecked(&mut self, data: &[u8]) -> usize {
self.__write_bytes_unchecked(data)
}
#[inline]
pub const unsafe fn try_write_bytes_unchecked(
&mut self,
data: &[u8],
) -> Result<usize, StackOverflow> {
self.__try_write_bytes_unchecked(data)
}
#[inline]
pub const unsafe fn write_byte(&mut self, data: u8) -> usize {
self.__write_byte(data)
}
#[inline]
pub const unsafe fn try_write_byte(&mut self, data: u8) -> Result<usize, StackOverflow> {
self.__try_write_byte(data)
}
#[inline]
pub const unsafe fn get_mut(&mut self, pos: usize) -> Option<&mut u8> {
self._get_mut(pos)
}
#[inline]
pub const unsafe fn pop(&mut self) -> Option<u8> {
self._pop()
}
#[inline]
pub const unsafe fn as_mut_bytes(&mut self) -> &mut [u8] {
self._as_mut_bytes()
}
#[inline]
#[cfg_attr(docsrs, doc(cfg(feature = "clufulltransmute")))]
#[cfg(feature = "clufulltransmute")]
pub const fn into_array_filled_with_zero(self) -> (usize, [u8; CAP]) {
self._into_array(b' ') }
#[inline]
#[cfg_attr(docsrs, doc(cfg(feature = "clufulltransmute")))]
#[cfg(feature = "clufulltransmute")]
pub const fn into_array_filled_with_space(self) -> (usize, [u8; CAP]) {
self._into_array(b' ') }
#[inline]
#[cfg_attr(docsrs, doc(cfg(feature = "clufulltransmute")))]
#[cfg(feature = "clufulltransmute")]
pub const unsafe fn into_array(self, space: u8) -> (usize, [u8; CAP]) {
self._into_array(space)
}
}
impl<const CAP: usize> ConstByteBuf<CAP, DefBuf> {
#[track_caller]
#[inline]
pub const fn write_bytes(&mut self, data: &[u8]) -> usize {
self.__write_bytes_unchecked(data)
}
#[inline]
pub const fn try_write_bytes(&mut self, data: &[u8]) -> Result<usize, StackOverflow> {
self.__try_write_bytes_unchecked(data)
}
#[track_caller]
#[inline]
pub const fn write_byte(&mut self, data: u8) -> usize {
self.__write_byte(data)
}
#[inline]
pub const fn try_write_byte(&mut self, data: u8) -> Result<usize, StackOverflow> {
self.__try_write_byte(data)
}
#[inline]
pub const fn get_mut(&mut self, pos: usize) -> Option<&mut u8> {
self._get_mut(pos)
}
#[inline]
pub const fn pop(&mut self) -> Option<u8> {
self._pop()
}
#[inline]
pub const fn as_mut_bytes(&mut self) -> &mut [u8] {
self._as_mut_bytes()
}
#[inline]
#[cfg_attr(docsrs, doc(cfg(feature = "clufulltransmute")))]
#[cfg(feature = "clufulltransmute")]
pub const fn into_array(self, space: u8) -> (usize, [u8; CAP]) {
self._into_array(space) }
}
impl<const CAP: usize, TData> Clone for ConstByteBuf<CAP, TData>
where
TData: ConstByteBufData,
{
#[inline]
fn clone(&self) -> Self {
ConstByteBuf::clone(self)
}
}
impl<const CAP: usize, TData> Default for ConstByteBuf<CAP, TData>
where
TData: ConstByteBufData,
{
#[inline]
fn default() -> Self {
ConstByteBuf::new()
}
}
impl<const CAP: usize> Display for ConstByteBuf<CAP, Utf8SafeBuf> {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Display::fmt(self.as_str(), f)
}
}
impl<const CAP: usize> Debug for ConstByteBuf<CAP, DefBuf> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ConstByteBuf")
.field("buf", &self.as_bytes())
.field("wpos", &self.wpos)
.finish()
}
}
impl<const CAP: usize> Debug for ConstByteBuf<CAP, Utf8SafeBuf> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("ConstStrBuf")
.field("buf", &self.as_str())
.field("wpos", &self.wpos)
.finish()
}
}
impl<const CAP: usize, TData> Eq for ConstByteBuf<CAP, TData> where TData: ConstByteBufData {}
impl<const CAP: usize, TData> PartialEq for ConstByteBuf<CAP, TData>
where
TData: ConstByteBufData,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(self.as_bytes(), other.as_bytes())
}
}
impl<const CAP: usize> PartialEq<str> for ConstByteBuf<CAP, Utf8SafeBuf> {
#[inline]
fn eq(&self, other: &str) -> bool {
PartialEq::eq(self.as_str(), other)
}
}
impl<const CAP: usize> PartialEq<&'_ str> for ConstByteBuf<CAP, Utf8SafeBuf> {
#[inline]
fn eq(&self, other: &&str) -> bool {
PartialEq::eq(self.as_str(), *other)
}
}
impl<const CAP: usize, TData> PartialEq<[u8]> for ConstByteBuf<CAP, TData>
where
TData: ConstByteBufData,
{
#[inline]
fn eq(&self, other: &[u8]) -> bool {
PartialEq::eq(self.as_bytes(), other)
}
}
impl<const CAP: usize, TData> PartialEq<&'_ [u8]> for ConstByteBuf<CAP, TData>
where
TData: ConstByteBufData,
{
#[inline]
fn eq(&self, other: &&[u8]) -> bool {
PartialEq::eq(self.as_bytes(), *other)
}
}
impl<const CAP: usize, TData> PartialEq<&'_ mut [u8]> for ConstByteBuf<CAP, TData>
where
TData: ConstByteBufData,
{
#[inline]
fn eq(&self, other: &&mut [u8]) -> bool {
PartialEq::eq(self.as_bytes(), *other)
}
}
impl<const CAP: usize, TData> Hash for ConstByteBuf<CAP, TData>
where
TData: ConstByteBufData,
{
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
Hash::hash(self.as_bytes(), state)
}
}
#[repr(transparent)]
pub struct StackOverflow;