hvec 0.2.0

A Vec-like structure that can store different types of different sizes contiguous with each other in memory.
Documentation
//! In memory of Anna Harren, who coined the term
//! [turbofish](https://turbo.fish/) - which you'll see a lot of
//! if you use this crate.
//!
//! The main purpose of this crate is the `HarrenVec` type -
//! a [`Vec`]-like data structure that can store items
//! of different types and sizes from each other.
//!
//! Values of any type can be stored, and they are
//! stored contiguous in memory like a normal [`Vec`] would.
//!
//! The intended use case for this data structure is
//! efficiently packing structs with large optional fields,
//! while avoiding [`Box`]-ing those values.
//!
//! It supports values with a [`Drop`] implementation by default.
//!
//! However, if you include the `no_drop` feature, then
//! dropping the `HarrenVec` will _not_ call the destructors of
//! the contents. Instead you should use the
//! [`HarrenVec::into_iter`] method to ensure you are consuming
//! and dropping values correctly. If the values do not have
//! destructors, this is not necessary.
//!
//! # Examples
//! ```
//! use hvec::HarrenVec;
//!
//! struct SmallMessage {
//!     id: usize,
//!     has_extra: bool,
//! }
//!
//! struct LargeExtraField {
//!     data: [[f64; 4]; 4],
//! }
//!
//! let mut messages = HarrenVec::new();
//! messages.push(SmallMessage { id: 0, has_extra: false });
//! messages.push(SmallMessage { id: 1, has_extra: true });
//! messages.push(LargeExtraField { data: [[0.; 4]; 4] });
//! messages.push(SmallMessage { id: 2, has_extra: false });
//!
//! let mut iter = messages.into_iter();
//! while let Some(message) = iter.next::<SmallMessage>() {
//!     println!("id = {}", message.id);
//!     if message.has_extra {
//!         let extra = iter.next::<LargeExtraField>().unwrap();
//!         println!("extra data = {:?}", extra.data);
//!     }
//! }
//!
//! // Output:
//! // id = 0
//! // id = 1
//! // extra data = [[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]]
//! // id = 2
//! ```

use std::any::TypeId;
use std::mem::MaybeUninit;

#[cfg(not(feature = "no_drop"))]
use std::{cell::RefCell, collections::HashMap};

#[cfg(not(feature = "no_drop"))]
type Destructor = Box<dyn Fn(*const ())>;

#[cfg(not(feature = "no_drop"))]
thread_local! {
    static DESTRUCTORS: RefCell<HashMap<TypeId, Destructor>> = RefCell::new(HashMap::new());
}

#[cfg(not(feature = "no_drop"))]
fn register_destructor<T: 'static>() {
    DESTRUCTORS.with(|destructors| {
        let mut destructors = destructors.borrow_mut();
        let type_id = TypeId::of::<T>();
        destructors.entry(type_id).or_insert_with(|| {
            Box::new(|ptr: *const ()| {
                let ptr = ptr as *const T;
                unsafe {
                    ptr.read();
                }
            })
        });
    });
}

#[cfg(not(feature = "no_drop"))]
fn run_destructor(type_id: TypeId, ptr: *const ()) {
    DESTRUCTORS.with(|destructors| {
        let destructors = destructors.borrow();
        let destructor = &destructors[&type_id];
        destructor(ptr);
    });
}

/// A [`Vec`]-like data structure that can store items
/// of different types and sizes from each other.
///
/// Values of any type can be stored, and they are
/// stored contiguous in memory like a normal [`Vec`] would.
///
/// The intended use case for this data structure is
/// efficiently packing structs with large optional fields,
/// while avoiding [`Box`]-ing those values.
///
/// It supports values with a [`Drop`] implementation by default.
///
/// However, if you include the `no_drop` feature, then
/// dropping the `HarrenVec` will _not_ call the destructors of
/// the contents. Instead you should use the
/// [`HarrenVec::into_iter`] method to ensure you are consuming
/// and dropping values correctly. If the values do not have
/// destructors, this is not necessary.
///
/// # Examples
/// ```
/// use hvec::HarrenVec;
///
/// struct SmallMessage {
///     id: usize,
///     has_extra: bool,
/// }
///
/// struct LargeExtraField {
///     data: [[f64; 4]; 4],
/// }
///
/// let mut messages = HarrenVec::new();
/// messages.push(SmallMessage { id: 0, has_extra: false });
/// messages.push(SmallMessage { id: 1, has_extra: true });
/// messages.push(LargeExtraField { data: [[0.; 4]; 4] });
/// messages.push(SmallMessage { id: 2, has_extra: false });
///
/// let mut iter = messages.into_iter();
/// while let Some(message) = iter.next::<SmallMessage>() {
///     println!("id = {}", message.id);
///     if message.has_extra {
///         let extra = iter.next::<LargeExtraField>().unwrap();
///         println!("extra data = {:?}", extra.data);
///     }
/// }
///
/// // Output:
/// // id = 0
/// // id = 1
/// // extra data = [[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]]
/// // id = 2
/// ```
#[derive(Debug, Default, Clone)]
pub struct HarrenVec {
    types: Vec<TypeId>,
    indices: Vec<usize>,
    backing: Vec<u8>,
}

/// Type alias for [`HarrenVec`].
pub type HVec = HarrenVec;

impl HarrenVec {
    /// Constructs a new empty [`HarrenVec`].
    ///
    /// # Examples
    /// ```
    /// # use hvec::HarrenVec;
    /// let mut list = HarrenVec::new();
    /// ```
    pub fn new() -> Self {
        Self::default()
    }

    /// Constructs a new empty [`HarrenVec`] with at least the
    /// specified capacity in items and bytes.
    ///
    /// The `HarrenVec` stores the types of the data separately
    /// from the data. In practice, it will re-allocate if
    /// either of these capacities are exceeded.
    ///
    /// # Examples
    /// ```
    /// # use hvec::HarrenVec;
    /// let mut list = HarrenVec::with_capacity(4, 64);
    /// assert!(list.item_capacity() >= 4);
    /// assert!(list.byte_capacity() >= 64);
    /// ```
    pub fn with_capacity(items: usize, bytes: usize) -> Self {
        HarrenVec {
            types: Vec::with_capacity(items),
            indices: Vec::with_capacity(items),
            backing: Vec::with_capacity(bytes),
        }
    }

    /// Reserve capacity for at least `items` more items and
    /// `bytes` more bytes.
    pub fn reserve(&mut self, items: usize, bytes: usize) {
        self.types.reserve(items);
        self.indices.reserve(items);
        self.backing.reserve(bytes);
    }

    /// Reserve capacity for at least `items` more items and
    /// `bytes` more bytes. (Attempts to reserve the minimum
    /// possible, but this is not guaranteed.)
    pub fn reserve_exact(&mut self, items: usize, bytes: usize) {
        self.types.reserve_exact(items);
        self.indices.reserve_exact(items);
        self.backing.reserve_exact(bytes);
    }

    /// Reserve capacity for at least `items` more items and
    /// `bytes` more bytes.
    ///
    /// # Errors
    /// Returns an error if allocation fails.
    pub fn try_reserve(
        &mut self,
        items: usize,
        bytes: usize,
    ) -> Result<(), std::collections::TryReserveError> {
        self.types.try_reserve(items)?;
        self.indices.try_reserve(items)?;
        self.backing.try_reserve(bytes)?;
        Ok(())
    }

    /// Reserve capacity for at least `items` more items and
    /// `bytes` more bytes. (Attempts to reserve the minimum
    /// possible, but this is not guaranteed.)
    ///
    /// # Errors
    /// Returns an error if allocation fails.
    pub fn try_reserve_exact(
        &mut self,
        items: usize,
        bytes: usize,
    ) -> Result<(), std::collections::TryReserveError> {
        self.types.try_reserve_exact(items)?;
        self.indices.try_reserve_exact(items)?;
        self.backing.try_reserve_exact(bytes)?;
        Ok(())
    }

    /// Move all elements from another `HarrenVec` into
    /// this one, leaving the `other` empty.
    ///
    /// # Examples
    /// ```
    /// # use hvec::hvec;
    /// let mut a = hvec![1, 2, 3];
    /// let mut b = hvec![4, 5, 6];
    /// a.append(&mut b);
    /// assert_eq!(a.len(), 6);
    /// assert_eq!(b.len(), 0);
    /// ```
    pub fn append(&mut self, other: &mut HarrenVec) {
        let mut offset = 0;
        for i in 0..other.len() {
            let end = other
                .indices
                .get(i + 1)
                .copied()
                .unwrap_or(other.backing.len());

            self.indices.push(self.backing.len());
            self.backing.extend_from_slice(&other.backing[offset..end]);
            self.types.push(other.types[i]);

            offset = end;
        }
        other.clear_without_drop();
    }

    /// Clears the contents of the `HarrenVec`.
    ///
    /// (Note that if the `no_drop` feature is enabled, then
    /// this method will not call the destructors of any of its contents.
    ///
    /// If the contents do not have a [`Drop`] implementation, this is not a
    /// concern.)
    pub fn clear(&mut self) {
        #[cfg(not(feature = "no_drop"))]
        {
            for i in 0..self.len() {
                self.drop_item(i);
            }
        }
        self.clear_without_drop();
    }

    fn clear_without_drop(&mut self) {
        self.types.clear();
        self.indices.clear();
        self.backing.clear();
    }

    /// Truncates the contents of the `HarrenVec` to a set
    /// number of items, clearing the rest.
    ///
    /// (Note that if the `no_drop` feature is enabled, then
    /// this method will not call the destructors of any of its contents.
    ///
    /// If the contents do not have a [`Drop`] implementation, this is not a
    /// concern.)
    pub fn truncate(&mut self, items: usize) {
        #[cfg(not(feature = "no_drop"))]
        {
            let end = items + 1;
            if end < self.len() {
                for i in end..self.len() {
                    self.drop_item(i);
                }
            }
        }
        if let Some(last_index) = self.indices.get(items).copied() {
            self.types.truncate(items);
            self.indices.truncate(items);
            self.backing.truncate(last_index);
        }
    }

    /// Returns the type of the last item in the `HarrenVec`.
    ///
    /// # Examples
    /// ```
    /// # use hvec::hvec;
    /// use std::any::TypeId;
    ///
    /// let list = hvec![1_u8, 2_i32, 3_u64];
    /// assert_eq!(list.peek_type(), Some(TypeId::of::<u64>()));
    /// ```
    pub fn peek_type(&self) -> Option<TypeId> {
        self.types.last().copied()
    }

    /// Returns the type of the last item in the `HarrenVec`,
    /// as well as a pointer to the first byte of it.
    ///
    /// # Safety
    ///
    /// The pointer returned points to memory owned by the
    /// `HarrenVec`, and so it is only valid as long as it that
    /// data is unchanged.
    ///
    /// # Examples
    /// ```
    /// # use hvec::hvec;
    /// use std::any::TypeId;
    ///
    /// let list = hvec![1_u8, 2_i32, 3_u64];
    /// let (type_id, ptr) = list.peek_ptr().unwrap();
    ///
    /// assert_eq!(type_id, TypeId::of::<u64>());
    ///
    /// unsafe {
    ///     let ptr = ptr as *const u64;
    ///     assert_eq!(*ptr, 3_u64);
    /// }
    /// ```
    pub fn peek_ptr(&self) -> Option<(TypeId, *const u8)> {
        self.types.last().map(|&type_id| {
            let index = self.indices.last().unwrap();
            (type_id, &self.backing[*index] as *const u8)
        })
    }

    /// Returns the number of items in the `HarrenVec`.
    pub fn len(&self) -> usize {
        self.indices.len()
    }

    /// Returns the total number of bytes occupied by the
    /// contents of the `HarrenVec`.
    pub fn bytes_len(&self) -> usize {
        self.backing.len()
    }

    /// Returns `true` if there are no contents.
    pub fn is_empty(&self) -> bool {
        self.indices.is_empty()
    }

    /// Returns an Iterator-like structure for stepping through
    /// the contents of the `HarrenVec`.
    ///
    /// Note that because the type of each item can be
    /// different, and may not be known, this "iterator" cannot
    /// be used in `for` loops.
    ///
    /// # Examples
    ///
    /// The recommended way to use this method depends on how
    /// much you know about the contents. If there is a main
    /// type and you know in advance when that type will
    /// deviate, you can use a `while-let` loop:
    ///
    /// ```
    /// # use hvec::hvec;
    /// let list = hvec![1_usize, 2_usize, 999_usize, "Wow, big number!".to_string(), 3_usize];
    /// let mut iter = list.into_iter();
    ///
    /// let mut total = 0;
    /// while let Some(number) = iter.next::<usize>() {
    ///     if number > 100 {
    ///         let comment = iter.next::<String>().unwrap();
    ///         assert_eq!(comment, "Wow, big number!");
    ///     }
    ///     total += number;
    /// }
    /// assert_eq!(total, 1005);
    /// ```
    ///
    /// If you don't have a structure that allows you to know
    /// what type the next element is in advance, you can check
    /// the type of each item as you read it:
    ///
    /// ```
    /// # use hvec::hvec;
    /// use std::any::TypeId;
    ///
    /// let list = hvec![1_u8, 500_u16, 99999_u32];
    /// let mut iter = list.into_iter();
    ///
    /// let mut total: usize = 0;
    /// while let Some(type_id) = iter.peek_type() {
    ///     if type_id == TypeId::of::<u8>() {
    ///         total += iter.next::<u8>().unwrap() as usize;
    ///     } else if type_id == TypeId::of::<u16>() {
    ///         total += iter.next::<u16>().unwrap() as usize;
    ///     } else if type_id == TypeId::of::<u32>() {
    ///         total += iter.next::<u32>().unwrap() as usize;
    ///     }
    /// }
    /// assert_eq!(total, 100500);
    /// ```
    #[allow(clippy::should_implement_trait)]
    pub fn into_iter(self) -> HarrenIter {
        HarrenIter {
            cursor: 0,
            vec: self,
        }
    }

    /// Returns an Iterator-like structure for stepping through immutable references to
    /// the contents of the `HarrenVec`.
    ///
    /// See [`HarrenVec::into_iter`] for examples.
    pub fn iter(&self) -> HarrenRefIter {
        HarrenRefIter {
            cursor: 0,
            vec: self,
        }
    }

    /// Returns an Iterator-like structure for stepping through mutable references to
    /// the contents of the `HarrenVec`.
    ///
    /// See [`HarrenVec::into_iter`] for examples.
    pub fn iter_mut(&mut self) -> HarrenMutIter {
        HarrenMutIter {
            cursor: 0,
            vec: self,
        }
    }

    /// Add an element of any type to the `HarrenVec`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use hvec::HarrenVec;
    /// let mut list = HarrenVec::new();
    /// list.push(1_u8);
    /// list.push("Hello, world!".to_string());
    /// assert_eq!(list.len(), 2);
    /// ```
    pub fn push<T: 'static>(&mut self, t: T) {
        let type_id = TypeId::of::<T>();
        let ptr = &t as *const T as *const u8;
        let size = std::mem::size_of::<T>();
        let bytes = unsafe { std::slice::from_raw_parts(ptr, size) };
        self.indices.push(self.backing.len());
        self.backing.extend_from_slice(bytes);
        self.types.push(type_id);

        #[cfg(not(feature = "no_drop"))]
        register_destructor::<T>();

        std::mem::forget(t);
    }

    /// Pop the last element from the `HarrenVec`.
    ///
    /// # Panics
    ///
    /// This method panics if the actual element is not an
    /// element of the specified type `T`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use hvec::hvec;
    /// let mut list = hvec!["Hello".to_string()];
    /// assert_eq!(list.pop::<String>().unwrap(), "Hello".to_string());
    /// ```
    pub fn pop<T: 'static>(&mut self) -> Option<T> {
        self.types.pop().map(|type_id| {
            let index = self.indices.pop().unwrap();
            assert_eq!(TypeId::of::<T>(), type_id);

            let result = unsafe { self.take_at::<T>(index) };
            self.backing.truncate(index);
            result
        })
    }

    unsafe fn ref_at<T>(&self, offset: usize) -> &T {
        std::mem::transmute(&self.backing[offset])
    }

    unsafe fn mut_ref_at<T>(&mut self, offset: usize) -> &mut T {
        std::mem::transmute(&mut self.backing[offset])
    }

    unsafe fn take_at<T>(&self, offset: usize) -> T {
        let mut result: MaybeUninit<T> = MaybeUninit::uninit();

        let ptr = &self.backing[offset] as *const u8 as *const T;
        let dest = result.as_mut_ptr();
        dest.copy_from(ptr, 1);
        result.assume_init()
    }

    #[cfg(not(feature = "no_drop"))]
    fn drop_item(&mut self, index: usize) {
        let type_id = self.types[index];
        let offset = self.indices[index];
        let ptr = &self.backing[offset] as *const u8 as *const ();
        run_destructor(type_id, ptr);
    }

    /// Returns true if this `HarrenVec` contains the element.
    ///
    /// # Examples
    /// ```
    /// # use hvec::hvec;
    /// let list = hvec![1_usize, "Hello".to_string()];
    /// assert!(list.contains::<usize>(&1));
    /// assert!(list.contains::<String>(&"Hello".to_string()));
    /// assert!(!list.contains::<isize>(&1));
    /// assert!(!list.contains::<String>(&"???".to_string()));
    /// ```
    pub fn contains<T: PartialEq<T> + 'static>(&self, x: &T) -> bool {
        for (item_index, type_id) in self.types.iter().enumerate() {
            if *type_id == TypeId::of::<T>()
                && unsafe { self.ref_at::<T>(self.indices[item_index]) == x }
            {
                return true;
            }
        }
        false
    }

    /// Return a reference to the first item of the `HarrenVec`.
    ///
    /// # Panics
    ///
    /// This method panics if the item is not of the specified
    /// type `T`.
    pub fn first<T: 'static>(&self) -> Option<&T> {
        assert_eq!(Some(&TypeId::of::<T>()), self.types.first());
        self.indices
            .first()
            .copied()
            .map(|i| unsafe { self.ref_at::<T>(i) })
    }

    /// Return a mutable reference to the first item of
    /// the `HarrenVec`.
    ///
    /// # Panics
    ///
    /// This method panics if the item is not of the specified
    /// type `T`.
    pub fn first_mut<T: 'static>(&mut self) -> Option<&mut T> {
        assert_eq!(Some(&TypeId::of::<T>()), self.types.first());
        self.indices
            .first()
            .copied()
            .map(|i| unsafe { self.mut_ref_at::<T>(i) })
    }

    /// Return a reference to the last item of the `HarrenVec`.
    ///
    /// # Panics
    ///
    /// This method panics if the item is not of the specified
    /// type `T`.
    pub fn last<T: 'static>(&self) -> Option<&T> {
        assert_eq!(Some(&TypeId::of::<T>()), self.types.last());
        self.indices
            .last()
            .copied()
            .map(|i| unsafe { self.ref_at::<T>(i) })
    }

    /// Return a mutable reference to the last item of
    /// the `HarrenVec`.
    ///
    /// # Panics
    ///
    /// This method panics if the item is not of the specified
    /// type `T`.
    pub fn last_mut<T: 'static>(&mut self) -> Option<&mut T> {
        assert_eq!(Some(&TypeId::of::<T>()), self.types.last());
        self.indices
            .last()
            .copied()
            .map(|i| unsafe { self.mut_ref_at::<T>(i) })
    }

    /// Alias of the `HarrenVec::last` method.
    pub fn peek<T: 'static>(&self) -> Option<&T> {
        self.last()
    }

    /// Alias of the `HarrenVec::last_mut` method.
    pub fn peek_mut<T: 'static>(&mut self) -> Option<&mut T> {
        self.last_mut()
    }

    /// Return a reference to the item of the `HarrenVec` at
    /// the given index.
    ///
    /// # Panics
    ///
    /// This method panics if the item is not of the specified
    /// type `T`.
    pub fn get<T: 'static>(&self, index: usize) -> Option<&T> {
        assert_eq!(Some(&TypeId::of::<T>()), self.types.get(index));
        self.indices
            .get(index)
            .copied()
            .map(|i| unsafe { self.ref_at::<T>(i) })
    }

    /// Return a mutable reference to the item of
    /// the `HarrenVec` at the given index.
    ///
    /// # Panics
    ///
    /// This method panics if the item is not of the specified
    /// type `T`.
    pub fn get_mut<T: 'static>(&mut self, index: usize) -> Option<&mut T> {
        assert_eq!(Some(&TypeId::of::<T>()), self.types.get(index));
        self.indices
            .get(index)
            .copied()
            .map(|i| unsafe { self.mut_ref_at::<T>(i) })
    }

    /// Returns the total number of elements this `HarrenVec`
    /// can store without reallocating.
    ///
    /// Note that this is separate from its capacity in bytes.
    /// Allocation will occur if either capacity is exceeded.
    pub fn item_capacity(&self) -> usize {
        std::cmp::min(self.types.capacity(), self.indices.capacity())
    }

    /// Returns the total number of bytes this `HarrenVec`
    /// can store without reallocating.
    ///
    /// Note that this is separate from its capacity in items.
    /// Allocation will occur if either capacity is exceeded.
    pub fn byte_capacity(&self) -> usize {
        self.backing.capacity()
    }

    /// Returns true if `other` contains the exact same types
    /// and bytes as this `HarrenVec`. Not that this does _not_
    /// call the actual [`PartialEq`] implementation for the
    /// stored values, so the result may not be intuitive for
    /// more complex or heap-allocated types.
    ///
    /// # Examples
    ///
    /// ```
    /// # use hvec::hvec;
    /// let list_a = hvec![1_u8, 2_isize];
    /// let list_b = hvec![1_u8, 2_isize];
    ///
    /// let list_c = hvec![1_u8, "Hello".to_string()];
    /// let list_d = hvec![1_u8, "Hello".to_string()];
    ///
    /// // Numbers can be correctly compared as bytes
    /// assert!(list_a.bytes_eq(&list_b));
    ///
    /// // Strings contain pointers so identical strings may differ in bytes
    /// assert!(!list_c.bytes_eq(&list_d));
    /// ```
    pub fn bytes_eq(&self, other: &HarrenVec) -> bool {
        self.types == other.types && self.indices == other.indices && self.backing == other.backing
    }
}

#[cfg(not(feature = "no_drop"))]
impl Drop for HarrenVec {
    fn drop(&mut self) {
        self.clear();
    }
}

/// An [`Iterator`]-like structure for taking
/// ownership of the elements of a [`HarrenVec`].
///
/// (Note that if the `no_drop` feature is enabled, then
/// this iterator will not call the destructors of any of its contents
/// when dropped. Instead you should use the `next` method to ensure
/// you are consuming and dropping each value.
///
/// If the contents do not have a [`Drop`] implementation, this is not a
/// concern.)
#[derive(Debug)]
pub struct HarrenIter {
    cursor: usize,
    vec: HarrenVec,
}

impl HarrenIter {
    /// Checks the type of the next item in the iterator
    /// without actually advancing it.
    ///
    /// # Examples
    /// ```
    /// use std::any::TypeId;
    /// use hvec::hvec;
    ///
    /// let list = hvec![1_u64, 2_i32];
    /// let mut iter = list.into_iter();
    /// assert_eq!(iter.peek_type(), Some(TypeId::of::<u64>()));
    /// ```
    pub fn peek_type(&self) -> Option<TypeId> {
        self.vec.types.get(self.cursor).copied()
    }

    /// Advances the iterator and returns the next item if
    /// one exists - or else None.
    ///
    /// # Panics
    ///
    /// This method will panic if the actual type of the item
    /// differs from the `T` that this method was called with.
    ///
    /// # Examples
    /// ```
    /// use hvec::hvec;
    ///
    /// let list = hvec![1_u64, 2_i32];
    /// let mut iter = list.into_iter();
    /// assert_eq!(iter.next::<u64>(), Some(1_u64));
    /// assert_eq!(iter.next::<i32>(), Some(2_i32));
    /// assert_eq!(iter.next::<()>(), None);
    /// ```
    #[allow(clippy::should_implement_trait)]
    pub fn next<T: 'static>(&mut self) -> Option<T> {
        if self.is_empty() {
            return None;
        }

        let type_id = self.vec.types[self.cursor];
        assert_eq!(type_id, TypeId::of::<T>());

        let index = self.vec.indices[self.cursor];
        let result = unsafe { self.vec.take_at::<T>(index) };
        self.cursor += 1;
        Some(result)
    }

    /// Returns true if there are no more elements in the
    /// iterator.
    pub fn is_empty(&self) -> bool {
        self.cursor >= self.vec.len()
    }
}

#[cfg(not(feature = "no_drop"))]
impl Drop for HarrenIter {
    fn drop(&mut self) {
        if !self.is_empty() {
            for i in self.cursor..self.vec.len() {
                self.vec.drop_item(i);
            }
        }
        self.vec.clear_without_drop();
    }
}

/// An [`Iterator`]-like structure for immutably borrowing
/// the elements of a [`HarrenVec`].
#[derive(Debug)]
pub struct HarrenRefIter<'a> {
    cursor: usize,
    vec: &'a HarrenVec,
}

impl<'a> HarrenRefIter<'a> {
    /// Checks the type of the next item in the iterator
    /// without actually advancing it.
    ///
    /// # Examples
    /// ```
    /// use std::any::TypeId;
    /// use hvec::hvec;
    ///
    /// let list = hvec![1_u64, 2_i32];
    /// let mut iter = list.into_iter();
    /// assert_eq!(iter.peek_type(), Some(TypeId::of::<u64>()));
    /// ```
    pub fn peek_type(&self) -> Option<TypeId> {
        self.vec.types.get(self.cursor).copied()
    }

    /// Advances the iterator and returns the next item if
    /// one exists - or else None.
    ///
    /// # Panics
    ///
    /// This method will panic if the actual type of the item
    /// differs from the `T` that this method was called with.
    ///
    /// # Examples
    /// ```
    /// use hvec::hvec;
    ///
    /// let list = hvec![1_u64, 2_i32];
    /// let mut iter = list.into_iter();
    /// assert_eq!(iter.next::<u64>(), Some(1_u64));
    /// assert_eq!(iter.next::<i32>(), Some(2_i32));
    /// assert_eq!(iter.next::<()>(), None);
    /// ```
    #[allow(clippy::should_implement_trait)]
    pub fn next<T: 'static>(&mut self) -> Option<&T> {
        if self.is_empty() {
            return None;
        }

        let type_id = self.vec.types[self.cursor];
        assert_eq!(type_id, TypeId::of::<T>());

        let index = self.vec.indices[self.cursor];
        let result = unsafe { self.vec.ref_at::<T>(index) };
        self.cursor += 1;
        Some(result)
    }

    /// Returns true if there are no more elements in the
    /// iterator.
    pub fn is_empty(&self) -> bool {
        self.cursor >= self.vec.len()
    }
}

/// An [`Iterator`]-like structure for mutably borrowing
/// the elements of a [`HarrenVec`].
#[derive(Debug)]
pub struct HarrenMutIter<'a> {
    cursor: usize,
    vec: &'a mut HarrenVec,
}

impl<'a> HarrenMutIter<'a> {
    /// Checks the type of the next item in the iterator
    /// without actually advancing it.
    ///
    /// # Examples
    /// ```
    /// use std::any::TypeId;
    /// use hvec::hvec;
    ///
    /// let list = hvec![1_u64, 2_i32];
    /// let mut iter = list.into_iter();
    /// assert_eq!(iter.peek_type(), Some(TypeId::of::<u64>()));
    /// ```
    pub fn peek_type(&self) -> Option<TypeId> {
        self.vec.types.get(self.cursor).copied()
    }

    /// Advances the iterator and returns the next item if
    /// one exists - or else None.
    ///
    /// # Panics
    ///
    /// This method will panic if the actual type of the item
    /// differs from the `T` that this method was called with.
    ///
    /// # Examples
    /// ```
    /// use hvec::hvec;
    ///
    /// let list = hvec![1_u64, 2_i32];
    /// let mut iter = list.into_iter();
    /// assert_eq!(iter.next::<u64>(), Some(1_u64));
    /// assert_eq!(iter.next::<i32>(), Some(2_i32));
    /// assert_eq!(iter.next::<()>(), None);
    /// ```
    #[allow(clippy::should_implement_trait)]
    pub fn next<T: 'static>(&mut self) -> Option<&mut T> {
        if self.is_empty() {
            return None;
        }

        let type_id = self.vec.types[self.cursor];
        assert_eq!(type_id, TypeId::of::<T>());

        let index = self.vec.indices[self.cursor];
        let result = unsafe { self.vec.mut_ref_at::<T>(index) };
        self.cursor += 1;
        Some(result)
    }

    /// Returns true if there are no more elements in the
    /// iterator.
    pub fn is_empty(&self) -> bool {
        self.cursor >= self.vec.len()
    }
}

/// Creates a [`HarrenVec`] containing the arguments.
///
/// # Examples
/// ```
/// use hvec::hvec;
///
/// let list_a = hvec![];
/// let list_b = hvec![1_u64; 2];
/// let list_c = hvec![1_u64, 2_i64, 3_u8];
///
/// assert!(list_a.len() == 0);
/// assert!(list_b.len() == 2);
/// assert!(list_c.len() == 3);
/// ```
#[macro_export]
macro_rules! hvec {
    () => { $crate::HarrenVec::new() };
    ($elem : expr ; $n : expr) => {{
        let mut vec = $crate::HarrenVec::new();
        for _ in 0..($n) {
            vec.push(($elem).clone());
        }
        vec
    }};
    ($($x : expr), + $(,) ?) => {{
        let mut vec = $crate::HarrenVec::new();
        $(vec.push($x);)*
        vec
    }};
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn construction_and_equality() {
        let macro_created = hvec![1_usize, 2_u8, [100_u32; 5]];
        let mut default = HVec::default();
        let mut with_cap = HVec::with_capacity(5, 64);

        {
            default.push(1_usize);
            default.push(2_u8);
            default.push([100_u32; 5]);
            with_cap.push(1_usize);
            with_cap.push(2_u8);
            with_cap.push([100_u32; 5]);
        }

        assert!(macro_created.bytes_eq(&default));
        assert!(default.bytes_eq(&with_cap));
        assert!(with_cap.bytes_eq(&macro_created));
    }

    #[test]
    fn macro_forms() {
        assert!(hvec![].bytes_eq(&HVec::default()));
        assert!(hvec![1_u8, 1_u8].bytes_eq(&hvec![1_u8; 2]));
    }

    #[test]
    fn bytes_eq_fails_for_strings() {
        let a = hvec!["Hello".to_string()];
        let b = hvec!["Hello".to_string()];
        assert!(!a.bytes_eq(&b));
    }

    #[test]
    fn capacity() {
        let mut list = HVec::with_capacity(2, 16);
        assert!(list.item_capacity() >= 2);
        assert!(list.byte_capacity() >= 16);

        list.push(1_u64);
        list.push(2_i64);
        list.push(3_u128);

        assert!(list.item_capacity() >= 3);
        assert!(list.byte_capacity() >= 32);
    }

    #[test]
    fn new_reserve() {
        let mut list = HVec::new();
        assert!(list.item_capacity() == 0);
        assert!(list.byte_capacity() == 0);

        list.reserve(4, 64);
        assert!(list.item_capacity() >= 4);
        assert!(list.byte_capacity() >= 64);
    }

    #[test]
    fn clear_truncate() {
        let mut list = hvec![1_u8, 2_i16, 3_u32, 4_i64];
        assert!(!list.is_empty());
        assert_eq!(list.len(), 4);

        list.truncate(2);
        assert_eq!(list.len(), 2);
        list.clear();
        assert_eq!(list.len(), 0);

        assert!(list.is_empty());
    }

    #[test]
    fn peek() {
        let list_a = hvec![11_u8, 22_i16, 33_u32];
        let list_b = hvec![11_u8, 22_i16];
        let list_c = hvec![11_u8];
        let list_d = hvec![];

        assert_eq!(list_a.peek_type(), Some(TypeId::of::<u32>()));
        assert_eq!(list_b.peek_type(), Some(TypeId::of::<i16>()));
        assert_eq!(list_c.peek_type(), Some(TypeId::of::<u8>()));
        assert_eq!(list_d.peek_type(), None);

        let (_, p_a) = list_a.peek_ptr().unwrap();
        let (_, p_b) = list_b.peek_ptr().unwrap();
        let (_, p_c) = list_c.peek_ptr().unwrap();

        unsafe {
            assert_eq!(*(p_a as *const u32), 33);
            assert_eq!(*(p_b as *const i16), 22);
            assert_eq!(*(p_c as *const u8), 11);
        }
    }

    #[test]
    fn append() {
        let mut a = hvec![1_u32, 2_u64, 3_u128];
        let mut b = hvec![4_i32, 5_i64, 6_i128];
        a.append(&mut b);

        assert!(a.len() == 6);
        assert!(b.is_empty());

        let mut iter = a.into_iter();
        assert_eq!(iter.next::<u32>(), Some(1_u32));
        assert_eq!(iter.next::<u64>(), Some(2_u64));
        assert_eq!(iter.next::<u128>(), Some(3_u128));
        assert_eq!(iter.next::<i32>(), Some(4_i32));
        assert_eq!(iter.next::<i64>(), Some(5_i64));
        assert_eq!(iter.next::<i128>(), Some(6_i128));
        assert_eq!(iter.next::<()>(), None);
    }

    #[test]
    fn push_peek_pop() {
        let mut list = hvec![];
        list.push(1_usize);
        list.push(2_u8);
        list.push("Hello".to_string());

        assert_eq!(list.peek::<String>().unwrap(), "Hello");
        assert_eq!(list.pop::<String>().unwrap(), "Hello");
        assert_eq!(list.peek::<u8>(), Some(&2));
        assert_eq!(list.pop::<u8>(), Some(2));
        assert_eq!(list.peek::<usize>(), Some(&1));
        assert_eq!(list.pop::<usize>(), Some(1));
    }

    #[test]
    fn first_last_get() {
        let a = hvec![1_u8, 2_isize, "3".to_string()];
        assert_eq!(a.first::<u8>(), Some(&1));
        assert_eq!(a.get::<isize>(1), Some(&2));
        assert_eq!(a.last::<String>(), Some(&"3".to_string()));
    }

    #[test]
    fn first_last_get_mut() {
        let mut a = hvec![1_u8, 2_isize, "3".to_string()];

        let target = a.first_mut::<u8>().unwrap();
        *target = 10;

        let target = a.get_mut::<isize>(1).unwrap();
        *target = 20;

        let target = a.last_mut::<String>().unwrap();
        *target = "30".to_string();

        assert_eq!(a.first::<u8>(), Some(&10));
        assert_eq!(a.get::<isize>(1), Some(&20));
        assert_eq!(a.last::<String>(), Some(&"30".to_string()));
    }

    #[test]
    fn contains() {
        let a = hvec![1_u8, 2_isize, "3".to_string()];
        assert!(a.contains::<u8>(&1));
        assert!(a.contains::<isize>(&2));
        assert!(a.contains::<String>(&"3".to_string()));
    }

    #[test]
    #[should_panic]
    fn wrong_first_panics() {
        let a = hvec![1_usize];
        a.first::<u8>();
    }

    #[test]
    #[should_panic]
    fn wrong_last_panics() {
        let a = hvec![1_usize];
        a.last::<u8>();
    }

    #[test]
    #[should_panic]
    fn wrong_get_panics() {
        let a = hvec![1_usize];
        a.get::<u8>(0);
    }

    #[test]
    #[should_panic]
    fn wrong_pop_panics() {
        let mut a = hvec![1_usize];
        a.pop::<u8>();
    }

    #[test]
    fn into_iter() {
        let mut list = HarrenVec::new();
        list.push(1_usize);
        list.push(2_u8);
        list.push("Hello".to_string());

        let mut items = list.into_iter();
        assert_eq!(items.peek_type(), Some(TypeId::of::<usize>()));
        assert_eq!(items.next::<usize>(), Some(1));
        assert_eq!(items.next::<u8>(), Some(2));
        assert_eq!(items.next::<String>(), Some("Hello".to_string()));
    }

    #[test]
    fn iter() {
        let mut list = HarrenVec::new();
        list.push(1_usize);
        list.push(2_u8);
        list.push("Hello".to_string());

        let mut items = list.iter();
        assert_eq!(items.peek_type(), Some(TypeId::of::<usize>()));
        assert_eq!(items.next::<usize>(), Some(&1));
        assert_eq!(items.next::<u8>(), Some(&2));
        assert_eq!(items.next::<String>(), Some(&"Hello".to_string()));
    }

    #[test]
    fn iter_mut() {
        let mut list = HarrenVec::new();
        list.push(1_usize);
        list.push(2_u8);
        list.push("Hello".to_string());

        let mut items = list.iter_mut();
        assert_eq!(items.peek_type(), Some(TypeId::of::<usize>()));
        assert_eq!(items.next::<usize>(), Some(&mut 1));
        assert_eq!(items.next::<u8>(), Some(&mut 2));
        assert_eq!(items.next::<String>(), Some(&mut "Hello".to_string()));
    }

    #[test]
    fn extra_props() {
        struct Entry {
            id: usize,
            extra: bool,
        }

        struct Extra {
            info: String,
        }

        let mut log = String::new();

        let mut list = HarrenVec::new();
        list.push(Entry {
            id: 0,
            extra: false,
        });
        list.push(Entry { id: 1, extra: true });
        list.push(Extra {
            info: "Hello".into(),
        });
        list.push(Entry {
            id: 2,
            extra: false,
        });

        let mut items = list.into_iter();
        while let Some(entry) = items.next::<Entry>() {
            log.push_str(&entry.id.to_string());
            if entry.extra {
                let extra = items.next::<Extra>().unwrap();
                log.push_str(&extra.info);
            }
        }

        assert_eq!(log, "01Hello2");
    }
}