$doc_hide
pub mod fixed_str_nz$len {
extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt::{Debug, Display, Formatter, Result as FmtResult};
use core::ops::{self, Deref, DerefMut, Index, IndexMut};
use core::borrow::{Borrow, BorrowMut};
use core::convert::{AsRef, AsMut};
use core::hash::{Hasher, Hash};
use core::cmp::Ordering;
use core::str::{Utf8Error, FromStr};
use core::num::NonZeroU8;
use core::mem::{transmute, transmute_copy};
/// A smart pointer to str with a fixed length of $len,which do not allow zeroes,for skip zeroes at
/// the end use the normal variant.
#[repr(transparent)]
#[derive(Clone, Copy)]$doc_hide
pub struct FixedStrNZ$len {
array: [NonZeroU8; $len],
}
impl FixedStrNZ$len {
/// Creates an FixedStrNZ$len from an array,returning an error at invalid utf8.
#[inline]
pub fn new(array: [NonZeroU8; $len]) -> Result<Self, Utf8Error> {
let fixed_str = Self { array };
core::str::from_utf8(fixed_str.as_bytes())?;
// this validates the utf8 bytes dropping the resulting str
Ok(fixed_str)
}
/// Creates an FixedStrNZ$len without checking if the bytes are valid utf8.
///
/// # Safety
///
/// Ensure to only use this method with valid utf8.
#[inline]
pub const unsafe fn new_unchecked(array: [NonZeroU8; $len]) -> Self {
Self { array }
}
/// Borrow the internal array as an slice.
#[inline]
pub fn as_bytes(&self) -> &[u8] {
unsafe { transmute(&self.array[..]) }
}
/// Borrow the internal array as a mutable slice.
///
/// # Safety
///
/// This is unsafe due to allow modifications that can produce invalid utf8.
#[inline]
pub unsafe fn as_bytes_mut(&mut self) -> &mut [NonZeroU8] {
&mut self.array[..]
}
/// Consume and returns the underlying array of non-zero bytes utf8 encoded.
#[inline]
pub const fn into_bytes(self) -> [NonZeroU8; $len] {
self.array
}
/// Convert the FixedStrNZ$len into a vector of bytes.
#[inline]
pub fn into_vec(self) -> Vec<NonZeroU8> {
let mut buf: Vec<NonZeroU8> = Vec::with_capacity($len);
unsafe { self.array.as_ptr().copy_to(buf.as_mut_ptr(), $len); buf.set_len($len) }
buf
}
/// Turn the FixedStrNZ$len into a string,moving the bytes.
#[inline]
pub fn into_string(self) -> String {
let mut vec = core::mem::ManuallyDrop::new(self.into_vec());
unsafe { String::from_raw_parts(vec.as_mut_ptr() as *mut u8, vec.len(), vec.capacity()) }
}
/// Construct a FixedStrNZ$len from bytes,without checking if it has length $len.
///
/// # Safety
///
/// This will trigger UB on slice's with length different than $len.
pub unsafe fn from_bytes_unchecked(s: &[NonZeroU8]) -> Self {
Self::new_unchecked(*core::mem::transmute_copy::<&'_ [NonZeroU8], &'_ [NonZeroU8; $len]>(&s))
}
/// Construct a FixedStrNZ$len from a str,without checking if it has length $len.
///
/// # Safety
///
/// This will trigger UB on str's with length different than $len.
#[inline]
pub unsafe fn from_str_unchecked<'a, T: Borrow<str> + ?Sized>(s: &'a T) -> FixedStrNZ$len {
Self::from_bytes_unchecked(transmute_copy(&(*s).borrow().as_bytes()))
}
}
impl Display for FixedStrNZ$len {
fn fmt(&self, f: &'_ mut Formatter) -> FmtResult {
write!(f, "{}", self.deref())
}
}
impl Debug for FixedStrNZ$len {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
write!(f, "{}", self)
}
}
impl Deref for FixedStrNZ$len {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
unsafe {
core::str::from_utf8_unchecked(self.as_bytes())
}
}
}
impl DerefMut for FixedStrNZ$len {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
core::str::from_utf8_unchecked_mut(core::mem::transmute(self.as_bytes_mut()))
}
}
}
impl AsRef<str> for FixedStrNZ$len {
fn as_ref(&self) -> &str {
<Self as Deref>::deref(self)
}
}
impl AsMut<str> for FixedStrNZ$len {
fn as_mut(&mut self) -> &mut str {
<Self as DerefMut>::deref_mut(self)
}
}
impl From<&[NonZeroU8]> for FixedStrNZ$len {
/// Construct a FixedStrNZ$len from bytes non-zero of length greater or equal to $len,if it is
/// greater will take $len bytes.
///
/// # Panics
///
/// This will panic if the length of `s` is less than $len or if it is greater on debug.
#[inline]
fn from(s: &[NonZeroU8]) -> Self {
macro_rules! foo {
($s:expr) => {
core::str::from_utf8(core::mem::transmute($s))
.expect("slice had invalid utf8 when trying to convert to FixedStr$len")
};
}
if s.len() == $len {
unsafe {
Self::from_str_unchecked(foo!(s))
}
} else if s.len() > $len {
if cfg!(debug_assertions) {
panic!("the length of the string was greater than $len on debug")
}
unsafe {
Self::from_str_unchecked(&foo!(s)[..$len])
}
} else {
panic!("the length of the string was less than $len")
}
}
}
impl From<&str> for FixedStrNZ$len {
/// Construct a FixedStrNZ$len from a string of length greater or equal to $len,if it is
/// greater will take $len bytes so be careful with no ascii letters.
///
/// # Panics
///
/// This will panic if the length of `s` is less than $len and if it is greater on debug.
#[inline]
fn from(s: &str) -> Self {
if s.len() == $len {
unsafe {
Self::from_str_unchecked(s)
}
} else if s.len() > $len {
if cfg!(debug_assertions) {
panic!("the length of the string was greater than $len on debug")
}
unsafe {
Self::from_str_unchecked(&s[..$len])
}
} else {
panic!("the length of the string was less than $len")
}
}
}
impl Eq for FixedStrNZ$len {}
impl Hash for FixedStrNZ$len {
fn hash<H: Hasher>(&self, state: &mut H) {
self.deref().hash(state)
}
}
impl Borrow<str> for FixedStrNZ$len {
fn borrow(&self) -> &str {
self.deref()
}
}
impl BorrowMut<str> for FixedStrNZ$len {
fn borrow_mut(&mut self) -> &mut str {
self.deref_mut()
}
}
impl<T: Borrow<str> + ?Sized> PartialOrd<T> for FixedStrNZ$len {
fn partial_cmp(&self, other: &T) -> Option<Ordering> {
self.deref().partial_cmp((*other).borrow())
}
}
impl Ord for FixedStrNZ$len {
fn cmp(&self, other: &Self) -> Ordering {
self.deref().cmp(other.deref())
}
}
impl ops::Index<ops::Range<usize>> for FixedStrNZ$len {
type Output = str;
#[inline]
fn index(&self, index: ops::Range<usize>) -> &str {
&self[..][index]
}
}
impl ops::Index<ops::RangeTo<usize>> for FixedStrNZ$len {
type Output = str;
#[inline]
fn index(&self, index: ops::RangeTo<usize>) -> &str {
&self[..][index]
}
}
impl ops::Index<ops::RangeFrom<usize>> for FixedStrNZ$len {
type Output = str;
#[inline]
fn index(&self, index: ops::RangeFrom<usize>) -> &str {
&self[..][index]
}
}
impl ops::Index<ops::RangeFull> for FixedStrNZ$len {
type Output = str;
#[inline]
fn index(&self, _index: ops::RangeFull) -> &str {
self.deref()
}
}
impl ops::Index<ops::RangeInclusive<usize>> for FixedStrNZ$len {
type Output = str;
#[inline]
fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
Index::index(self.deref(), index)
}
}
impl ops::Index<ops::RangeToInclusive<usize>> for FixedStrNZ$len {
type Output = str;
#[inline]
fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
Index::index(self.deref(), index)
}
}
impl ops::IndexMut<ops::Range<usize>> for FixedStrNZ$len {
#[inline]
fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
&mut self[..][index]
}
}
impl ops::IndexMut<ops::RangeTo<usize>> for FixedStrNZ$len {
#[inline]
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
&mut self[..][index]
}
}
impl ops::IndexMut<ops::RangeFrom<usize>> for FixedStrNZ$len {
#[inline]
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
&mut self[..][index]
}
}
impl ops::IndexMut<ops::RangeFull> for FixedStrNZ$len {
#[inline]
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
self.deref_mut()
}
}
impl ops::IndexMut<ops::RangeInclusive<usize>> for FixedStrNZ$len {
#[inline]
fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
IndexMut::index_mut(self.deref_mut(), index)
}
}
impl ops::IndexMut<ops::RangeToInclusive<usize>> for FixedStrNZ$len {
#[inline]
fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
IndexMut::index_mut(self.deref_mut(), index)
}
}
impl<T: Borrow<str> + ?Sized> PartialEq<T> for FixedStrNZ$len {
#[inline]
fn eq<'a>(&self, other: &'a T) -> bool { PartialEq::eq(&self[..], (*other).borrow()) }
#[inline]
fn ne<'a>(&self, other: &'a T) -> bool { PartialEq::ne(&self[..], (*other).borrow()) }
}
impl FromStr for FixedStrNZ$len {
type Err = core::convert::Infallible;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(s.into())
}
}