use core::fmt;
#[derive(Debug)]
pub struct Fstr<const N: usize> {
bytes: [u8; N],
size: usize,
trimmed: bool,
}
impl<const N: usize> fmt::Display for Fstr<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.as_str() {
Some(s) => write!(f, "{s}"),
None => write!(f, "{:?}", &self.bytes[0..self.size]),
}
}
}
impl<const N: usize> Fstr<N> {
fn new(bytes: &[u8], trimmed: bool) -> Fstr<N> {
let size = bytes.len();
let mut f = Fstr {
bytes: [0; N],
size,
trimmed,
};
f.bytes[0..size].copy_from_slice(bytes);
f
}
pub fn as_bytes(&self) -> &[u8] {
&self.bytes[0..self.size]
}
pub fn as_str(&self) -> Option<&str> {
core::str::from_utf8(self.as_bytes()).ok()
}
pub fn capacity(&self) -> usize {
N
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn is_trimmed(&self) -> bool {
self.trimmed
}
pub fn len(&self) -> usize {
self.size
}
}
impl<const N: usize> From<&[u8]> for Fstr<N> {
fn from(bytes: &[u8]) -> Self {
let size = bytes.len().min(N);
let trimmed = size < bytes.len();
Fstr::<N>::new(&bytes[0..size], trimmed)
}
}
impl<const N: usize> From<&str> for Fstr<N> {
fn from(s: &str) -> Self {
let bytes = s.as_bytes();
let mut size = bytes.len().min(N);
if N > 0 && bytes.len() > N {
for truncate in 0..size.min(4) {
let tsize = size - truncate;
if core::str::from_utf8(&bytes[0..tsize]).is_ok() {
size = tsize;
break;
}
}
}
let trimmed = size < bytes.len();
Fstr::<N>::new(&bytes[0..size], trimmed)
}
}