fashex 0.0.8

Hexadecimal string encoding and decoding with best-effort SIMD acceleration.
Documentation
use core::mem::MaybeUninit;
use core::slice;

/// An output buffer for encoding or decoding hexadecimal strings.
pub trait Buffer {
    /// Returns the uninitialized portion of the buffer where the encoded or
    /// decoded bytes can be written to.
    fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>];

    #[allow(unsafe_code, reason = "See below.")]
    /// Advances the initialized length of the buffer by `additional` bytes
    /// (when applicable) and returns the newly initialized portion of the
    /// buffer.
    ///
    /// This marks the next `additional` bytes (starting from the current
    /// initialized offset) as initialized, setting the new initialized
    /// length to `current + additional`.
    ///
    /// ## Safety
    ///
    /// 1. `additional` <= `self.spare_capacity_mut().len()`.
    /// 1. `additional` bytes starting from the current initialized offset are
    ///    properly initialized.
    unsafe fn advance(&mut self, additional: usize) -> &[u8];
}

impl<T: Buffer> Buffer for &mut T {
    #[inline]
    fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
        Buffer::spare_capacity_mut(*self)
    }

    #[inline]
    #[allow(unsafe_code, reason = "XXX")]
    unsafe fn advance(&mut self, additional: usize) -> &[u8] {
        unsafe { Buffer::advance(*self, additional) }
    }
}

impl Buffer for [MaybeUninit<u8>] {
    #[inline]
    fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
        self
    }

    #[inline]
    #[allow(unsafe_code, reason = "XXX")]
    unsafe fn advance(&mut self, additional: usize) -> &[u8] {
        debug_assert!(additional <= self.len());

        unsafe { slice::from_raw_parts(self.as_ptr().cast(), additional) }
    }
}

impl<const N: usize> Buffer for [MaybeUninit<u8>; N] {
    #[inline]
    fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
        self
    }

    #[inline]
    #[allow(unsafe_code, reason = "XXX")]
    unsafe fn advance(&mut self, additional: usize) -> &[u8] {
        debug_assert!(additional <= N);

        unsafe { slice::from_raw_parts(self.as_ptr().cast(), additional) }
    }
}

impl Buffer for [u8] {
    #[inline]
    fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
        #[allow(unsafe_code, reason = "XXX")]
        unsafe {
            &mut *((&raw mut *self) as *mut [MaybeUninit<u8>])
        }
    }

    #[inline]
    #[allow(unsafe_code, reason = "XXX")]
    unsafe fn advance(&mut self, additional: usize) -> &[u8] {
        debug_assert!(additional <= self.len());

        unsafe { slice::from_raw_parts(self.as_ptr(), additional) }
    }
}

impl<const N: usize> Buffer for [u8; N] {
    #[inline]
    fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
        #[allow(unsafe_code, reason = "XXX")]
        unsafe {
            &mut *((&raw mut *self).cast::<[MaybeUninit<u8>; N]>())
        }
    }

    #[inline]
    #[allow(unsafe_code, reason = "XXX")]
    unsafe fn advance(&mut self, additional: usize) -> &[u8] {
        debug_assert!(additional <= N);

        unsafe { slice::from_raw_parts(self.as_ptr(), additional) }
    }
}

#[cfg(feature = "alloc")]
impl Buffer for alloc::vec::Vec<u8> {
    #[inline]
    fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
        self.spare_capacity_mut()
    }

    #[inline]
    #[allow(unsafe_code, reason = "XXX")]
    unsafe fn advance(&mut self, additional: usize) -> &[u8] {
        let len = self.len();

        unsafe {
            self.set_len(len + additional);
        }

        &self[len..]
    }
}