turbocow 0.3.0-beta.2

Compact, clone-on-write vectors, strings, maps and sets with inline + referenced storage — a superset of ecow.
Documentation
use core::ptr;

use crate::allocator::AllocatorProvider;
use crate::dynamic::common::limit::LEN_VALUE_MASK_USIZE;
use crate::dynamic::types::DynamicVec;

impl<'a, const N: usize, A> Clone for DynamicVec<'a, N, A>
where
    A: AllocatorProvider + Clone,
{
    #[inline]
    fn clone(&self) -> Self {
        if self.is_referenced() {
            // Clone Referenced separately to preserve pointer provenance.
            // Copying the raw pointer through the InlineVec byte-array
            // view strips Miri provenance, causing UB when dereferenced.
            let r = unsafe { &*self.0.referenced };
            let len = r.len & LEN_VALUE_MASK_USIZE;
            // Safety: r.ptr was created from a &'a [u8] in from_referenced,
            // so reconstituting the slice with the original lifetime is sound.
            let slice = unsafe { core::slice::from_raw_parts(r.ptr, len) };
            Self::from_referenced(slice, r.allocator.clone())
        } else if self.is_inline() {
            Self::from_inline(unsafe { (*self.0.inline).clone() })
        } else {
            Self::from_eco(unsafe { (*self.0.spilled).clone() })
        }
    }
}

impl<const N: usize, A> Drop for DynamicVec<'_, N, A>
where
    A: AllocatorProvider,
{
    #[inline]
    fn drop(&mut self) {
        // `is_inline()` returns true for both Inline and Referenced variants
        // (both have bit 7 set in tagged_len), so `!is_inline()` identifies
        // exactly the Spilled variant.  This avoids the full 3-way variant
        // dispatch that `variant_mut()` performs (saving one branch).
        if !self.is_inline() {
            unsafe {
                // Safety: We are guaranteed to have a valid `EcoVec`.
                ptr::drop_in_place(&mut *self.0.spilled);
            }
        }
        // Inline and Referenced don't own heap memory that needs dropping.
        // The allocator field inside ManuallyDrop is not dropped, but
        // Global (the typical allocator) is a ZST with no Drop impl.
    }
}

impl<const N: usize, A> PartialEq for DynamicVec<'_, N, A>
where
    A: AllocatorProvider,
{
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        // is_inline() is true for both Inline and Referenced (bit 7 set).
        // !is_inline() identifies exactly the Spilled variant.
        let si = self.is_inline();
        let oi = other.is_inline();
        if !si & !oi {
            // Both Spilled: EcoVec::PartialEq has a pointer-identity
            // fast-path for clones that share the same backing allocation.
            unsafe { *self.0.spilled == *other.0.spilled }
        } else {
            // At least one operand is Inline or Referenced: compare by
            // content. A raw-byte comparison is unsound here because
            // (1) inline tail bytes `[len..N)` are not guaranteed zero after
            //     shrinking ops (`truncate`, `clear`), and
            // (2) Inline and Referenced encode the same content with different
            //     bytes (an inline buffer vs. a pointer + length),
            // so equal-content values can have differing raw bytes.
            self.as_slice() == other.as_slice()
        }
    }
}

impl<const N: usize, A> Eq for DynamicVec<'_, N, A> where A: AllocatorProvider {}

impl<const N: usize, A> core::fmt::Debug for DynamicVec<'_, N, A>
where
    A: AllocatorProvider,
{
    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
        f.debug_struct("DynamicVec")
            .field("referenced", &self.is_referenced())
            .field("inline", &self.is_inline())
            .field("len", &self.len())
            .field("data", &self.as_slice())
            .finish()
    }
}