#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
#[doc(hidden)] pub struct ArrayStr<const N: usize> {
bytes: [u8; N],
len: u8,
}
impl<const N: usize> ArrayStr<N> {
pub(crate) const fn new(s: &str) -> Option<ArrayStr<N>> {
let len = s.len();
if len > N {
return None;
}
let mut bytes = [0; N];
let mut i = 0;
while i < s.as_bytes().len() {
bytes[i] = s.as_bytes()[i];
i += 1;
}
debug_assert!(N <= u8::MAX as usize, "size of ArrayStr is too big");
Some(ArrayStr { bytes, len: len as u8 })
}
pub(crate) fn capacity() -> usize {
N
}
pub(crate) fn push_str(&mut self, s: &str) -> bool {
let len = usize::from(self.len);
let Some(new_len) = len.checked_add(s.len()) else { return false };
if new_len > N {
return false;
}
self.bytes[len..new_len].copy_from_slice(s.as_bytes());
debug_assert!(
N <= usize::from(u8::MAX),
"size of ArrayStr is too big"
);
self.len = u8::try_from(new_len).unwrap();
true
}
pub(crate) fn as_str(&self) -> &str {
core::str::from_utf8(&self.bytes[..usize::from(self.len)]).unwrap()
}
}
impl<const N: usize> From<&'static str> for ArrayStr<N> {
fn from(s: &'static str) -> ArrayStr<N> {
ArrayStr::new(s).unwrap()
}
}
impl<const N: usize> PartialEq<str> for ArrayStr<N> {
fn eq(&self, rhs: &str) -> bool {
self.as_str() == rhs
}
}
impl<const N: usize> PartialEq<&str> for ArrayStr<N> {
fn eq(&self, rhs: &&str) -> bool {
self.as_str() == *rhs
}
}
impl<const N: usize> PartialEq<ArrayStr<N>> for str {
fn eq(&self, rhs: &ArrayStr<N>) -> bool {
self == rhs.as_str()
}
}
impl<const N: usize> core::fmt::Debug for ArrayStr<N> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Debug::fmt(self.as_str(), f)
}
}
impl<const N: usize> core::fmt::Display for ArrayStr<N> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Display::fmt(self.as_str(), f)
}
}
impl<const N: usize> core::fmt::Write for ArrayStr<N> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
if self.push_str(s) {
Ok(())
} else {
Err(core::fmt::Error)
}
}
}
impl<const N: usize> AsRef<str> for ArrayStr<N> {
fn as_ref(&self) -> &str {
self.as_str()
}
}
const ABBREVIATION_MAX: usize = 30;
#[doc(hidden)] pub type Abbreviation = ArrayStr<ABBREVIATION_MAX>;
#[cfg(test)]
mod tests {
use core::fmt::Write;
use super::*;
#[test]
fn fmt_write() {
let mut dst = ArrayStr::<5>::new("").unwrap();
assert!(write!(&mut dst, "abcd").is_ok());
assert!(write!(&mut dst, "e").is_ok());
assert!(write!(&mut dst, "f").is_err());
}
}