fashex 0.0.11

Hexadecimal string encoding and decoding with best-effort SIMD acceleration.
Documentation
use alloc::vec::Vec;
use core::fmt;

use crate::encode;

wrapper_lite::wrapper!(
    #[wrapper(Debug)]
    #[wrapper(AsRef)]
    #[wrapper([const] AsMut)]
    #[wrapper(BorrowMut)]
    #[wrapper(DerefMut)]
    #[wrapper(From)]
    #[bound(T: AsRef<[u8]>)]
    #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
    #[derive(Clone, Copy, PartialEq, Eq)]
    /// A wrapper for displaying a byte slice as a hexadecimal string.
    ///
    /// ```rust
    /// let bytes = &[0xde, 0xad, 0xbe, 0xef];
    ///
    /// let displayed = fashex::Display::from(bytes);
    ///
    /// assert_eq!(format!("{}", &displayed), "deadbeef");
    /// assert_eq!(format!("{:X}", &displayed), "DEADBEEF");
    /// assert_eq!(format!("{:#x}", &displayed), "0xdeadbeef");
    /// assert_eq!(format!("{:#X}", &displayed), "0xDEADBEEF");
    /// ```
    pub struct Display<T> {
        value: T,
    }
);

impl<T: AsRef<[u8]>> fmt::Display for Display<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl<T: AsRef<[u8]>> fmt::LowerHex for Display<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.write::<false>(f)
    }
}

impl<T: AsRef<[u8]>> fmt::UpperHex for Display<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.write::<true>(f)
    }
}

impl<T> Display<T>
where
    T: AsRef<[u8]>,
{
    fn write<const UPPER: bool>(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let src = self.as_inner().as_ref();

        let mut buf = Vec::with_capacity(src.len() * 2 + 2);

        if f.alternate() {
            buf.extend(b"0x");
        }

        encode::<UPPER>(src, &mut buf).map_err(|_| fmt::Error)?;

        #[allow(unsafe_code, reason = "XXX")]
        let buf = unsafe { str::from_utf8_unchecked(&buf) };

        f.write_str(buf)
    }
}