fixed_len_str 0.3.3

A procedural macro for create a smart pointer to str backed by a fixed size array,with the size given by the tokens.
Documentation
$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())
        }
    }