use std::fmt;
use std::fmt::{Debug, Display};
use std::marker::PhantomData;
#[derive(Clone, Copy, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub struct FixStr<const N: usize> {
inline: [u8; N],
len: u8,
_marker: PhantomData<[u8; N]>,
}
impl<const N: usize> Debug for FixStr<N> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FixStr(\"{}\")", self.as_str())
}
}
impl<const N: usize> Default for FixStr<N> {
fn default() -> Self {
Self {
inline: [0; N],
len: 0,
_marker: PhantomData,
}
}
}
impl<const N: usize> FixStr<N> {
#[must_use]
pub fn new(s: &str) -> Option<Self> {
if s.len() > N || s.len() > u8::MAX as usize {
return None;
}
let mut buffer = [0u8; N];
buffer[..s.len()].copy_from_slice(s.as_bytes());
u8::try_from(s.len()).ok().map(|len| Self {
inline: buffer,
len,
_marker: PhantomData,
})
}
#[must_use]
pub fn new_unchecked(s: &str) -> Self {
Self::new(s)
.unwrap_or_else(|| panic!("String '{s}' (len={}) exceeds capacity {N}", s.len()))
}
#[must_use]
pub fn as_str(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(&self.inline[..self.len as usize]) }
}
#[must_use]
pub fn char_len(&self) -> usize {
self.as_str().chars().count()
}
#[must_use]
pub fn len(&self) -> usize {
self.len as usize
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[must_use]
pub fn capacity(&self) -> usize {
N
}
}
impl<const N: usize> TryFrom<&str> for FixStr<N> {
type Error = String;
fn try_from(s: &str) -> Result<Self, Self::Error> {
Self::new(s).ok_or(format!(
"String '{s}' (len={}) exceeds capacity {N}",
s.len()
))
}
}
impl<const N: usize> TryFrom<String> for FixStr<N> {
type Error = String;
fn try_from(s: String) -> Result<Self, Self::Error> {
Self::try_from(s.as_str())
}
}
impl<const N: usize> From<FixStr<N>> for String {
fn from(s: FixStr<N>) -> Self {
String::from(s.as_str())
}
}
impl<const N: usize> AsRef<str> for FixStr<N> {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<const N: usize> fmt::Display for FixStr<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}