//! Contains the secondary map implementation.

#[cfg(all(nightly, any(doc, feature = "unstable")))]
use alloc::collections::TryReserveError;
use alloc::vec::Vec;
use core::hint::unreachable_unchecked;
use core::iter::{Enumerate, Extend, FromIterator, FusedIterator};
use core::marker::PhantomData;
use core::mem::replace;
#[allow(unused_imports)] // MaybeUninit is only used on nightly at the moment.
use core::mem::MaybeUninit;
use core::num::NonZeroU32;
use core::ops::{Index, IndexMut};

use super::{Key, KeyData};
use crate::util::is_older_version;

// This representation works because we don't have to store the versions
// of removed elements.
#[derive(Debug, Clone)]
enum Slot<T> {
    Occupied { value: T, version: NonZeroU32 },

    Vacant,
}

use self::Slot::{Occupied, Vacant};

impl<T> Slot<T> {
    pub fn new_occupied(version: u32, value: T) -> Self {
        Occupied {
            value,
            version: unsafe { NonZeroU32::new_unchecked(version | 1u32) },
        }
    }

    pub fn new_vacant() -> Self {
        Vacant
    }

    // Is this slot occupied?
    #[inline(always)]
    pub fn occupied(&self) -> bool {
        match self {
            Occupied { .. } => true,
            Vacant => false,
        }
    }

    #[inline(always)]
    pub fn version(&self) -> u32 {
        match self {
            Occupied { version, .. } => version.get(),
            Vacant => 0,
        }
    }

    pub unsafe fn get_unchecked(&self) -> &T {
        match self {
            Occupied { value, .. } => value,
            Vacant => unreachable_unchecked(),
        }
    }

    pub unsafe fn get_unchecked_mut(&mut self) -> &mut T {
        match self {
            Occupied { value, .. } => value,
            Vacant => unreachable_unchecked(),
        }
    }

    pub fn into_option(self) -> Option<T> {
        match self {
            Occupied { value, .. } => Some(value),
            Vacant => None,
        }
    }
}

/// Secondary map, associate data with previously stored elements in a slot map.
///
/// A [`SecondaryMap`] allows you to efficiently store additional information
/// for each element in a slot map. You can have multiple secondary maps per
/// slot map, but not multiple slot maps per secondary map. It is safe but
/// unspecified behavior if you use keys from multiple different slot maps in
/// the same [`SecondaryMap`].
///
/// A [`SecondaryMap`] does not leak memory even if you never remove elements.
/// In return, when you remove a key from the primary slot map, after any insert
/// the space associated with the removed element may be reclaimed. Don't expect
/// the values associated with a removed key to stick around after an insertion
/// has happened!
///
/// Finally a note on memory complexity, the [`SecondaryMap`] can use memory for
/// each slot in the primary slot map, and has to iterate over every slot during
/// iteration, regardless of whether you have inserted an associative value at
/// that key or not. If you have some property that you only expect to set for a
/// minority of keys, use a [`SparseSecondaryMap`](crate::SparseSecondaryMap),
/// which is backed by a [`HashMap`](std::collections::HashMap).
///
/// Example usage:
///
/// ```
/// # use slotmap::*;
/// let mut players = SlotMap::new();
/// let mut health = SecondaryMap::new();
/// let mut ammo = SecondaryMap::new();
///
/// let alice = players.insert("alice");
/// let bob = players.insert("bob");
///
/// for p in players.keys() {
///     health.insert(p, 100);
///     ammo.insert(p, 30);
/// }
///
/// // Alice attacks Bob with all her ammo!
/// health[bob] -= ammo[alice] * 3;
/// ammo[alice] = 0;
/// ```
#[derive(Debug, Clone)]
pub struct SecondaryMap<K: Key, V> {
    slots: Vec<Slot<V>>,
    num_elems: usize,
    _k: PhantomData<fn(K) -> K>,
}

impl<K: Key, V> SecondaryMap<K, V> {
    /// Constructs a new, empty [`SecondaryMap`].
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sec: SecondaryMap<DefaultKey, i32> = SecondaryMap::new();
    /// ```
    pub fn new() -> Self {
        Self::with_capacity(0)
    }

    /// Creates an empty [`SecondaryMap`] with the given capacity of slots.
    ///
    /// The secondary map will not reallocate until it holds at least `capacity`
    /// slots. Even inserting a single key-value pair might require as many
    /// slots as the slot map the key comes from, so it's recommended to match
    /// the capacity of a secondary map to its corresponding slot map.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm: SlotMap<_, i32> = SlotMap::with_capacity(10);
    /// let mut sec: SecondaryMap<DefaultKey, i32> = SecondaryMap::with_capacity(sm.capacity());
    /// ```
    pub fn with_capacity(capacity: usize) -> Self {
        let mut slots = Vec::with_capacity(capacity + 1); // Sentinel.
        slots.push(Slot::new_vacant());
        Self {
            slots,
            num_elems: 0,
            _k: PhantomData,
        }
    }

    /// Returns the number of elements in the secondary map.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let k = sm.insert(4);
    /// let mut squared = SecondaryMap::new();
    /// assert_eq!(squared.len(), 0);
    /// squared.insert(k, 16);
    /// assert_eq!(squared.len(), 1);
    /// ```
    pub fn len(&self) -> usize {
        self.num_elems
    }

    /// Returns if the secondary map is empty.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sec: SecondaryMap<DefaultKey, i32> = SecondaryMap::new();
    /// assert!(sec.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        self.num_elems == 0
    }

    /// Returns the number of elements the [`SecondaryMap`] can hold without
    /// reallocating.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sec: SecondaryMap<DefaultKey, i32> = SecondaryMap::with_capacity(10);
    /// assert!(sec.capacity() >= 10);
    /// ```
    pub fn capacity(&self) -> usize {
        self.slots.capacity() - 1 // Sentinel.
    }

    /// Sets the capacity of the [`SecondaryMap`] to `new_capacity`, if it is
    /// bigger than the current capacity.
    ///
    /// It is recommended to set the capacity of a [`SecondaryMap`] to the
    /// capacity of its corresponding slot map before inserting many new
    /// elements to prevent frequent reallocations. The collection may reserve
    /// more space than requested.
    ///
    /// # Panics
    ///
    /// Panics if the new allocation size overflows [`usize`].
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sec: SecondaryMap<DefaultKey, i32> = SecondaryMap::with_capacity(10);
    /// assert!(sec.capacity() >= 10);
    /// sec.set_capacity(1000);
    /// assert!(sec.capacity() >= 1000);
    /// ```
    pub fn set_capacity(&mut self, new_capacity: usize) {
        let new_capacity = new_capacity + 1; // Sentinel.
        if new_capacity > self.slots.capacity() {
            let needed = new_capacity - self.slots.len();
            self.slots.reserve(needed);
        }
    }

    /// Tries to set the capacity of the [`SecondaryMap`] to `new_capacity`, if it
    /// is bigger than the current capacity.
    ///
    /// It is recommended to set the capacity of a [`SecondaryMap`] to the
    /// capacity of its corresponding slot map before inserting many new
    /// elements to prevent frequent reallocations. The collection may reserve
    /// more space than requested.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sec: SecondaryMap<DefaultKey, i32> = SecondaryMap::with_capacity(10);
    /// assert!(sec.capacity() >= 10);
    /// sec.try_set_capacity(1000).unwrap();
    /// assert!(sec.capacity() >= 1000);
    /// ```
    #[cfg(all(nightly, any(doc, feature = "unstable")))]
    #[cfg_attr(all(nightly, doc), doc(cfg(feature = "unstable")))]
    pub fn try_set_capacity(&mut self, new_capacity: usize) -> Result<(), TryReserveError> {
        let new_capacity = new_capacity + 1; // Sentinel.
        if new_capacity > self.slots.capacity() {
            let needed = new_capacity - self.slots.len();
            self.slots.try_reserve(needed)
        } else {
            Ok(())
        }
    }

    /// Returns [`true`] if the secondary map contains `key`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let k = sm.insert(4);
    /// let mut squared = SecondaryMap::new();
    /// assert!(!squared.contains_key(k));
    /// squared.insert(k, 16);
    /// assert!(squared.contains_key(k));
    /// ```
    pub fn contains_key(&self, key: K) -> bool {
        let kd = key.data();
        self.slots
            .get(kd.idx as usize)
            .map_or(false, |slot| slot.version() == kd.version.get())
    }

    /// Inserts a value into the secondary map at the given `key`. Can silently
    /// fail and return `None` if `key` was removed from the originating slot
    /// map.
    ///
    /// Returns [`None`] if this key was not present in the map, the old value
    /// otherwise.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let k = sm.insert(4);
    /// let mut squared = SecondaryMap::new();
    /// assert_eq!(squared.insert(k, 0), None);
    /// assert_eq!(squared.insert(k, 4), Some(0));
    /// // You don't have to use insert if the key is already in the secondary map.
    /// squared[k] *= squared[k];
    /// assert_eq!(squared[k], 16);
    /// ```
    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
        if key.is_null() {
            return None;
        }

        let kd = key.data();
        self.slots
            .extend((self.slots.len()..=kd.idx as usize).map(|_| Slot::new_vacant()));

        let slot = &mut self.slots[kd.idx as usize];
        if slot.version() == kd.version.get() {
            // Is always occupied.
            return Some(replace(unsafe { slot.get_unchecked_mut() }, value));
        }

        if slot.occupied() {
            // Don't replace existing newer values.
            if is_older_version(kd.version.get(), slot.version()) {
                return None;
            }
        } else {
            self.num_elems += 1;
        }

        *slot = Slot::new_occupied(kd.version.get(), value);
        None
    }

    /// Removes a key from the secondary map, returning the value at the key if
    /// the key was not previously removed. If `key` was removed from the
    /// originating slot map, its corresponding entry in the secondary map may
    /// or may not already be removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut squared = SecondaryMap::new();
    /// let k = sm.insert(4);
    /// squared.insert(k, 16);
    /// squared.remove(k);
    /// assert!(!squared.contains_key(k));
    ///
    /// // It's not necessary to remove keys deleted from the primary slot map, they
    /// // get deleted automatically when their slots are reused on a subsequent insert.
    /// squared.insert(k, 16);
    /// sm.remove(k); // Remove k from the slot map, making an empty slot.
    /// let new_k = sm.insert(2); // Since sm only has one empty slot, this reuses it.
    /// assert!(!squared.contains_key(new_k)); // Space reuse does not mean equal keys.
    /// assert!(squared.contains_key(k)); // Slot has not been reused in squared yet.
    /// squared.insert(new_k, 4);
    /// assert!(!squared.contains_key(k)); // Old key is no longer available.
    /// ```
    pub fn remove(&mut self, key: K) -> Option<V> {
        let kd = key.data();
        if let Some(slot) = self.slots.get_mut(kd.idx as usize) {
            if slot.version() == kd.version.get() {
                self.num_elems -= 1;
                return replace(slot, Slot::new_vacant()).into_option();
            }
        }

        None
    }

    /// Retains only the elements specified by the predicate.
    ///
    /// In other words, remove all key-value pairs `(k, v)` such that
    /// `f(k, &mut v)` returns false. This method invalidates any removed keys.
    ///
    /// This function must iterate over all slots, empty or not. In the face of
    /// many deleted elements it can be inefficient.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let k1 = sm.insert(0); sec.insert(k1, 10);
    /// let k2 = sm.insert(1); sec.insert(k2, 11);
    /// let k3 = sm.insert(2); sec.insert(k3, 12);
    ///
    /// sec.retain(|key, val| key == k1 || *val == 11);
    ///
    /// assert!(sec.contains_key(k1));
    /// assert!(sec.contains_key(k2));
    /// assert!(!sec.contains_key(k3));
    /// assert_eq!(sec.len(), 2);
    /// ```
    pub fn retain<F>(&mut self, mut f: F)
    where
        F: FnMut(K, &mut V) -> bool,
    {
        for (i, slot) in self.slots.iter_mut().enumerate() {
            if let Occupied { value, version } = slot {
                let key = KeyData::new(i as u32, version.get()).into();
                if !f(key, value) {
                    self.num_elems -= 1;
                    *slot = Slot::new_vacant();
                }
            }
        }
    }

    /// Clears the secondary map. Keeps the allocated memory for reuse.
    ///
    /// This function must iterate over all slots, empty or not. In the face of
    /// many deleted elements it can be inefficient.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    /// for i in 0..10 {
    ///     sec.insert(sm.insert(i), i);
    /// }
    /// assert_eq!(sec.len(), 10);
    /// sec.clear();
    /// assert_eq!(sec.len(), 0);
    /// ```
    pub fn clear(&mut self) {
        self.drain();
    }

    /// Clears the slot map, returning all key-value pairs in arbitrary order as
    /// an iterator. Keeps the allocated memory for reuse.
    ///
    /// When the iterator is dropped all elements in the slot map are removed,
    /// even if the iterator was not fully consumed. If the iterator is not
    /// dropped (using e.g. [`std::mem::forget`]), only the elements that were
    /// iterated over are removed.
    ///
    /// This function must iterate over all slots, empty or not. In the face of
    /// many deleted elements it can be inefficient.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use std::iter::FromIterator;
    /// let mut sm = SlotMap::new();
    /// let k = sm.insert(0);
    /// let mut sec = SecondaryMap::new();
    /// sec.insert(k, 1);
    /// let v: Vec<_> = sec.drain().collect();
    /// assert_eq!(sec.len(), 0);
    /// assert_eq!(v, vec![(k, 1)]);
    /// ```
    pub fn drain(&mut self) -> Drain<K, V> {
        Drain { cur: 1, sm: self }
    }

    /// Returns a reference to the value corresponding to the key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let key = sm.insert("foo");
    /// let mut sec = SecondaryMap::new();
    /// sec.insert(key, "bar");
    /// assert_eq!(sec.get(key), Some(&"bar"));
    /// sec.remove(key);
    /// assert_eq!(sec.get(key), None);
    /// ```
    pub fn get(&self, key: K) -> Option<&V> {
        let kd = key.data();
        self.slots
            .get(kd.idx as usize)
            .filter(|slot| slot.version() == kd.version.get())
            .map(|slot| unsafe { slot.get_unchecked() })
    }

    /// Returns a reference to the value corresponding to the key without
    /// version or bounds checking.
    ///
    /// # Safety
    ///
    /// This should only be used if `contains_key(key)` is true. Otherwise it is
    /// potentially unsafe.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let key = sm.insert("foo");
    /// let mut sec = SecondaryMap::new();
    /// sec.insert(key, "bar");
    /// assert_eq!(unsafe { sec.get_unchecked(key) }, &"bar");
    /// sec.remove(key);
    /// // sec.get_unchecked(key) is now dangerous!
    /// ```
    pub unsafe fn get_unchecked(&self, key: K) -> &V {
        debug_assert!(self.contains_key(key));
        let slot = self.slots.get_unchecked(key.data().idx as usize);
        slot.get_unchecked()
    }

    /// Returns a mutable reference to the value corresponding to the key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let key = sm.insert("test");
    /// let mut sec = SecondaryMap::new();
    /// sec.insert(key, 3.5);
    /// if let Some(x) = sec.get_mut(key) {
    ///     *x += 3.0;
    /// }
    /// assert_eq!(sec[key], 6.5);
    /// ```
    pub fn get_mut(&mut self, key: K) -> Option<&mut V> {
        let kd = key.data();
        self.slots
            .get_mut(kd.idx as usize)
            .filter(|slot| slot.version() == kd.version.get())
            .map(|slot| unsafe { slot.get_unchecked_mut() })
    }

    /// Returns a mutable reference to the value corresponding to the key
    /// without version or bounds checking.
    ///
    /// # Safety
    ///
    /// This should only be used if `contains_key(key)` is true. Otherwise it is
    /// potentially unsafe.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let key = sm.insert("foo");
    /// let mut sec = SecondaryMap::new();
    /// sec.insert(key, "bar");
    /// unsafe { *sec.get_unchecked_mut(key) = "baz" };
    /// assert_eq!(sec[key], "baz");
    /// sec.remove(key);
    /// // sec.get_unchecked_mut(key) is now dangerous!
    /// ```
    pub unsafe fn get_unchecked_mut(&mut self, key: K) -> &mut V {
        debug_assert!(self.contains_key(key));
        let slot = self.slots.get_unchecked_mut(key.data().idx as usize);
        slot.get_unchecked_mut()
    }

    /// Returns mutable references to the values corresponding to the given
    /// keys. All keys must be valid and disjoint, otherwise None is returned.
    ///
    /// Requires at least stable Rust version 1.51.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    /// let ka = sm.insert(()); sec.insert(ka, "butter");
    /// let kb = sm.insert(()); sec.insert(kb, "apples");
    /// let kc = sm.insert(()); sec.insert(kc, "charlie");
    /// sec.remove(kc); // Make key c invalid.
    /// assert_eq!(sec.get_disjoint_mut([ka, kb, kc]), None); // Has invalid key.
    /// assert_eq!(sec.get_disjoint_mut([ka, ka]), None); // Not disjoint.
    /// let [a, b] = sec.get_disjoint_mut([ka, kb]).unwrap();
    /// std::mem::swap(a, b);
    /// assert_eq!(sec[ka], "apples");
    /// assert_eq!(sec[kb], "butter");
    /// ```
    #[cfg(has_min_const_generics)]
    pub fn get_disjoint_mut<const N: usize>(&mut self, keys: [K; N]) -> Option<[&mut V; N]> {
        // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
        // safe because the type we are claiming to have initialized here is a
        // bunch of `MaybeUninit`s, which do not require initialization.
        let mut ptrs: [MaybeUninit<*mut V>; N] = unsafe { MaybeUninit::uninit().assume_init() };
        let mut slot_versions: [MaybeUninit<u32>; N] =
            unsafe { MaybeUninit::uninit().assume_init() };

        let mut i = 0;
        while i < N {
            let kd = keys[i].data();

            match self.slots.get_mut(kd.idx as usize) {
                Some(Occupied { version, value }) if *version == kd.version => {
                    // This key is valid, and the slot is occupied. Temporarily
                    // set the version to 2 so duplicate keys would show up as
                    // invalid, since keys always have an odd version. This
                    // gives us a linear time disjointness check.
                    ptrs[i] = MaybeUninit::new(&mut *value);
                    slot_versions[i] = MaybeUninit::new(version.get());
                    *version = NonZeroU32::new(2).unwrap();
                },

                _ => break,
            }

            i += 1;
        }

        // Undo temporary unoccupied markings.
        for j in 0..i {
            let idx = keys[j].data().idx as usize;
            unsafe {
                match self.slots.get_mut(idx) {
                    Some(Occupied { version, .. }) => {
                        *version = NonZeroU32::new_unchecked(slot_versions[j].assume_init());
                    },
                    _ => unreachable_unchecked(),
                }
            }
        }

        if i == N {
            // All were valid and disjoint.
            Some(unsafe { core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs) })
        } else {
            None
        }
    }

    /// Returns mutable references to the values corresponding to the given
    /// keys. All keys must be valid and disjoint.
    ///
    /// Requires at least stable Rust version 1.51.
    ///
    /// # Safety
    ///
    /// This should only be used if `contains_key(key)` is true for every given
    /// key and no two keys are equal. Otherwise it is potentially unsafe.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    /// let ka = sm.insert(()); sec.insert(ka, "butter");
    /// let kb = sm.insert(()); sec.insert(kb, "apples");
    /// let [a, b] = unsafe { sec.get_disjoint_unchecked_mut([ka, kb]) };
    /// std::mem::swap(a, b);
    /// assert_eq!(sec[ka], "apples");
    /// assert_eq!(sec[kb], "butter");
    /// ```
    #[cfg(has_min_const_generics)]
    pub unsafe fn get_disjoint_unchecked_mut<const N: usize>(
        &mut self,
        keys: [K; N],
    ) -> [&mut V; N] {
        // Safe, see get_disjoint_mut.
        let mut ptrs: [MaybeUninit<*mut V>; N] = MaybeUninit::uninit().assume_init();
        for i in 0..N {
            ptrs[i] = MaybeUninit::new(self.get_unchecked_mut(keys[i]));
        }
        core::mem::transmute_copy::<_, [&mut V; N]>(&ptrs)
    }

    /// An iterator visiting all key-value pairs in arbitrary order. The
    /// iterator element type is `(K, &'a V)`.
    ///
    /// This function must iterate over all slots, empty or not. In the face of
    /// many deleted elements it can be inefficient.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    /// let k0 = sm.insert(0); sec.insert(k0, 10);
    /// let k1 = sm.insert(1); sec.insert(k1, 11);
    /// let k2 = sm.insert(2); sec.insert(k2, 12);
    ///
    /// for (k, v) in sm.iter() {
    ///     println!("key: {:?}, val: {}", k, v);
    /// }
    /// ```
    pub fn iter(&self) -> Iter<K, V> {
        Iter {
            num_left: self.num_elems,
            slots: self.slots.iter().enumerate(),
            _k: PhantomData,
        }
    }

    /// An iterator visiting all key-value pairs in arbitrary order, with
    /// mutable references to the values. The iterator element type is
    /// `(K, &'a mut V)`.
    ///
    /// This function must iterate over all slots, empty or not. In the face of
    /// many deleted elements it can be inefficient.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    /// let k0 = sm.insert(1); sec.insert(k0, 10);
    /// let k1 = sm.insert(2); sec.insert(k1, 20);
    /// let k2 = sm.insert(3); sec.insert(k2, 30);
    ///
    /// for (k, v) in sec.iter_mut() {
    ///     if k != k1 {
    ///         *v *= -1;
    ///     }
    /// }
    ///
    /// assert_eq!(sec[k0], -10);
    /// assert_eq!(sec[k1], 20);
    /// assert_eq!(sec[k2], -30);
    /// ```
    pub fn iter_mut(&mut self) -> IterMut<K, V> {
        IterMut {
            num_left: self.num_elems,
            slots: self.slots.iter_mut().enumerate(),
            _k: PhantomData,
        }
    }

    /// An iterator visiting all keys in arbitrary order. The iterator element
    /// type is `K`.
    ///
    /// This function must iterate over all slots, empty or not. In the face of
    /// many deleted elements it can be inefficient.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use std::collections::HashSet;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    /// let k0 = sm.insert(1); sec.insert(k0, 10);
    /// let k1 = sm.insert(2); sec.insert(k1, 20);
    /// let k2 = sm.insert(3); sec.insert(k2, 30);
    /// let keys: HashSet<_> = sec.keys().collect();
    /// let check: HashSet<_> = vec![k0, k1, k2].into_iter().collect();
    /// assert_eq!(keys, check);
    /// ```
    pub fn keys(&self) -> Keys<K, V> {
        Keys { inner: self.iter() }
    }

    /// An iterator visiting all values in arbitrary order. The iterator element
    /// type is `&'a V`.
    ///
    /// This function must iterate over all slots, empty or not. In the face of
    /// many deleted elements it can be inefficient.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use std::collections::HashSet;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    /// let k0 = sm.insert(1); sec.insert(k0, 10);
    /// let k1 = sm.insert(2); sec.insert(k1, 20);
    /// let k2 = sm.insert(3); sec.insert(k2, 30);
    /// let values: HashSet<_> = sec.values().collect();
    /// let check: HashSet<_> = vec![&10, &20, &30].into_iter().collect();
    /// assert_eq!(values, check);
    /// ```
    pub fn values(&self) -> Values<K, V> {
        Values { inner: self.iter() }
    }

    /// An iterator visiting all values mutably in arbitrary order. The iterator
    /// element type is `&'a mut V`.
    ///
    /// This function must iterate over all slots, empty or not. In the face of
    /// many deleted elements it can be inefficient.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use std::collections::HashSet;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    /// sec.insert(sm.insert(1), 10);
    /// sec.insert(sm.insert(2), 20);
    /// sec.insert(sm.insert(3), 30);
    /// sec.values_mut().for_each(|n| { *n *= 3 });
    /// let values: HashSet<_> = sec.into_iter().map(|(_k, v)| v).collect();
    /// let check: HashSet<_> = vec![30, 60, 90].into_iter().collect();
    /// assert_eq!(values, check);
    /// ```
    pub fn values_mut(&mut self) -> ValuesMut<K, V> {
        ValuesMut {
            inner: self.iter_mut(),
        }
    }

    /// Gets the given key's corresponding [`Entry`] in the map for in-place
    /// manipulation. May return [`None`] if the key was removed from the
    /// originating slot map.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    /// let k = sm.insert(1);
    /// let v = sec.entry(k).unwrap().or_insert(10);
    /// assert_eq!(*v, 10);
    /// ```
    pub fn entry(&mut self, key: K) -> Option<Entry<K, V>> {
        if key.is_null() {
            return None;
        }

        let kd = key.data();

        // Ensure the slot exists so the Entry implementation can safely assume
        // the slot always exists without checking.
        self.slots
            .extend((self.slots.len()..=kd.idx as usize).map(|_| Slot::new_vacant()));

        let slot = unsafe { self.slots.get_unchecked(kd.idx as usize) };
        if kd.version.get() == slot.version() {
            Some(Entry::Occupied(OccupiedEntry {
                map: self,
                kd,
                _k: PhantomData,
            }))
        } else if is_older_version(kd.version.get(), slot.version()) {
            None
        } else {
            Some(Entry::Vacant(VacantEntry {
                map: self,
                kd,
                _k: PhantomData,
            }))
        }
    }
}

impl<K: Key, V> Default for SecondaryMap<K, V> {
    fn default() -> Self {
        Self::new()
    }
}

impl<K: Key, V> Index<K> for SecondaryMap<K, V> {
    type Output = V;

    fn index(&self, key: K) -> &V {
        match self.get(key) {
            Some(r) => r,
            None => panic!("invalid SecondaryMap key used"),
        }
    }
}

impl<K: Key, V> IndexMut<K> for SecondaryMap<K, V> {
    fn index_mut(&mut self, key: K) -> &mut V {
        match self.get_mut(key) {
            Some(r) => r,
            None => panic!("invalid SecondaryMap key used"),
        }
    }
}

impl<K: Key, V: PartialEq> PartialEq for SecondaryMap<K, V> {
    fn eq(&self, other: &Self) -> bool {
        if self.len() != other.len() {
            return false;
        }

        self.iter()
            .all(|(key, value)| other.get(key).map_or(false, |other_value| *value == *other_value))
    }
}

impl<K: Key, V: Eq> Eq for SecondaryMap<K, V> {}

impl<K: Key, V> FromIterator<(K, V)> for SecondaryMap<K, V> {
    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
        let mut sec = Self::new();
        sec.extend(iter);
        sec
    }
}

impl<K: Key, V> Extend<(K, V)> for SecondaryMap<K, V> {
    fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
        let iter = iter.into_iter();
        for (k, v) in iter {
            self.insert(k, v);
        }
    }
}

impl<'a, K: Key, V: 'a + Copy> Extend<(K, &'a V)> for SecondaryMap<K, V> {
    fn extend<I: IntoIterator<Item = (K, &'a V)>>(&mut self, iter: I) {
        let iter = iter.into_iter();
        for (k, v) in iter {
            self.insert(k, *v);
        }
    }
}

/// A view into a occupied entry in a [`SecondaryMap`]. It is part of the
/// [`Entry`] enum.
#[derive(Debug)]
pub struct OccupiedEntry<'a, K: Key, V> {
    map: &'a mut SecondaryMap<K, V>,
    kd: KeyData,
    _k: PhantomData<fn(K) -> K>,
}

/// A view into a vacant entry in a [`SecondaryMap`]. It is part of the
/// [`Entry`] enum.
#[derive(Debug)]
pub struct VacantEntry<'a, K: Key, V> {
    map: &'a mut SecondaryMap<K, V>,
    kd: KeyData,
    _k: PhantomData<fn(K) -> K>,
}

/// A view into a single entry in a [`SecondaryMap`], which may either be
/// vacant or occupied.
///
/// This `enum` is constructed using [`SecondaryMap::entry`].
#[derive(Debug)]
pub enum Entry<'a, K: Key, V> {
    /// An occupied entry.
    Occupied(OccupiedEntry<'a, K, V>),

    /// A vacant entry.
    Vacant(VacantEntry<'a, K, V>),
}

impl<'a, K: Key, V> Entry<'a, K, V> {
    /// Ensures a value is in the entry by inserting the default if empty, and
    /// returns a mutable reference to the value in the entry.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let k = sm.insert("poneyland");
    /// let v = sec.entry(k).unwrap().or_insert(10);
    /// assert_eq!(*v, 10);
    /// *sec.entry(k).unwrap().or_insert(1) *= 2;
    /// assert_eq!(sec[k], 20);
    /// ```
    pub fn or_insert(self, default: V) -> &'a mut V {
        self.or_insert_with(|| default)
    }

    /// Ensures a value is in the entry by inserting the result of the default
    /// function if empty, and returns a mutable reference to the value in the
    /// entry.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let k = sm.insert(1);
    /// let v = sec.entry(k).unwrap().or_insert_with(|| "foobar".to_string());
    /// assert_eq!(v, &"foobar");
    /// ```
    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
        match self {
            Entry::Occupied(x) => x.into_mut(),
            Entry::Vacant(x) => x.insert(default()),
        }
    }

    /// Returns this entry's key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec: SecondaryMap<_, ()> = SecondaryMap::new();
    ///
    /// let k = sm.insert(1);
    /// let entry = sec.entry(k).unwrap();
    /// assert_eq!(entry.key(), k);
    /// ```
    pub fn key(&self) -> K {
        match self {
            Entry::Occupied(entry) => entry.kd.into(),
            Entry::Vacant(entry) => entry.kd.into(),
        }
    }

    /// Provides in-place mutable access to an occupied entry before any
    /// potential inserts into the map.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let k = sm.insert(1);
    /// sec.insert(k, 0);
    /// sec.entry(k).unwrap().and_modify(|x| *x = 1);
    ///
    /// assert_eq!(sec[k], 1)
    /// ```
    pub fn and_modify<F>(self, f: F) -> Self
    where
        F: FnOnce(&mut V),
    {
        match self {
            Entry::Occupied(mut entry) => {
                f(entry.get_mut());
                Entry::Occupied(entry)
            },
            Entry::Vacant(entry) => Entry::Vacant(entry),
        }
    }
}

impl<'a, K: Key, V: Default> Entry<'a, K, V> {
    /// Ensures a value is in the entry by inserting the default value if empty,
    /// and returns a mutable reference to the value in the entry.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec: SecondaryMap<_, Option<i32>> = SecondaryMap::new();
    ///
    /// let k = sm.insert(1);
    /// sec.entry(k).unwrap().or_default();
    /// assert_eq!(sec[k], None)
    /// ```
    pub fn or_default(self) -> &'a mut V {
        self.or_insert_with(Default::default)
    }
}

impl<'a, K: Key, V> OccupiedEntry<'a, K, V> {
    /// Returns this entry's key.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let k = sm.insert(1);
    /// sec.insert(k, 10);
    /// assert_eq!(sec.entry(k).unwrap().key(), k);
    /// ```
    pub fn key(&self) -> K {
        self.kd.into()
    }

    /// Removes the entry from the slot map and returns the key and value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use slotmap::secondary::Entry;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let foo = sm.insert("foo");
    /// sec.entry(foo).unwrap().or_insert("bar");
    ///
    /// if let Some(Entry::Occupied(o)) = sec.entry(foo) {
    ///     assert_eq!(o.remove_entry(), (foo, "bar"));
    /// }
    /// assert_eq!(sec.contains_key(foo), false);
    /// ```
    pub fn remove_entry(self) -> (K, V) {
        (self.kd.into(), self.remove())
    }

    /// Gets a reference to the value in the entry.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use slotmap::secondary::Entry;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let k = sm.insert(1);
    /// sec.insert(k, 10);
    ///
    /// if let Entry::Occupied(o) = sec.entry(k).unwrap() {
    ///     assert_eq!(*o.get(), 10);
    /// }
    /// ```
    pub fn get(&self) -> &V {
        unsafe { self.map.get_unchecked(self.kd.into()) }
    }

    /// Gets a mutable reference to the value in the entry.
    ///
    /// If you need a reference to the [`OccupiedEntry`] which may outlive the
    /// destruction of the [`Entry`] value, see [`into_mut`].
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use slotmap::secondary::Entry;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let k = sm.insert(1);
    /// sec.insert(k, 10);
    /// if let Entry::Occupied(mut o) = sec.entry(k).unwrap() {
    ///     *o.get_mut() = 20;
    /// }
    /// assert_eq!(sec[k], 20);
    /// ```
    ///
    /// [`into_mut`]: Self::into_mut
    pub fn get_mut(&mut self) -> &mut V {
        unsafe { self.map.get_unchecked_mut(self.kd.into()) }
    }

    /// Converts the [`OccupiedEntry`] into a mutable reference to the value in
    /// the entry with a lifetime bound to the map itself.
    ///
    /// If you need multiple references to the [`OccupiedEntry`], see
    /// [`get_mut`].
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use slotmap::secondary::Entry;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let k = sm.insert(0);
    /// sec.insert(k, 0);
    ///
    /// let r;
    /// if let Entry::Occupied(o) = sec.entry(k).unwrap() {
    ///     r = o.into_mut(); // v outlives the entry.
    /// } else {
    ///     r = sm.get_mut(k).unwrap();
    /// }
    /// *r = 1;
    /// assert_eq!((sm[k], sec[k]), (0, 1));
    /// ```
    ///
    /// [`get_mut`]: Self::get_mut
    pub fn into_mut(self) -> &'a mut V {
        unsafe { self.map.get_unchecked_mut(self.kd.into()) }
    }

    /// Sets the value of the entry, and returns the entry's old value.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use slotmap::secondary::Entry;
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let k = sm.insert(1);
    /// sec.insert(k, 10);
    ///
    /// if let Entry::Occupied(mut o) = sec.entry(k).unwrap() {
    ///     let v = o.insert(20);
    ///     assert_eq!(v, 10);
    ///     assert_eq!(*o.get(), 20);
    /// }
    /// ```
    pub fn insert(&mut self, value: V) -> V {
        replace(self.get_mut(), value)
    }

    /// Takes the value out of the entry, and returns it.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use slotmap::secondary::Entry;
    ///
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let k = sm.insert(1);
    /// sec.insert(k, 10);
    ///
    /// if let Entry::Occupied(mut o) = sec.entry(k).unwrap() {
    ///     assert_eq!(o.remove(), 10);
    ///     assert_eq!(sec.contains_key(k), false);
    /// }
    /// ```
    pub fn remove(self) -> V {
        let slot = unsafe { self.map.slots.get_unchecked_mut(self.kd.idx as usize) };
        self.map.num_elems -= 1;
        match replace(slot, Slot::new_vacant()) {
            Occupied { value, .. } => value,
            Vacant => unsafe { unreachable_unchecked() },
        }
    }
}

impl<'a, K: Key, V> VacantEntry<'a, K, V> {
    /// Gets the key that would be used when inserting a value through the
    /// [`VacantEntry`].
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use slotmap::secondary::Entry;
    ///
    /// let mut sm = SlotMap::new();
    /// let mut sec: SecondaryMap<_, ()> = SecondaryMap::new();
    ///
    /// let k = sm.insert(1);
    ///
    /// if let Entry::Vacant(v) = sec.entry(k).unwrap() {
    ///     assert_eq!(v.key(), k);
    /// }
    /// ```
    pub fn key(&self) -> K {
        self.kd.into()
    }

    /// Sets the value of the entry with the [`VacantEntry`]'s key, and returns
    /// a mutable reference to it.
    ///
    /// # Examples
    ///
    /// ```
    /// # use slotmap::*;
    /// # use slotmap::secondary::Entry;
    ///
    /// let mut sm = SlotMap::new();
    /// let mut sec = SecondaryMap::new();
    ///
    /// let k = sm.insert(1);
    ///
    /// if let Entry::Vacant(v) = sec.entry(k).unwrap() {
    ///     let new_val = v.insert(3);
    ///     assert_eq!(new_val, &mut 3);
    /// }
    /// ```
    pub fn insert(self, value: V) -> &'a mut V {
        let slot = unsafe { self.map.slots.get_unchecked_mut(self.kd.idx as usize) };
        // Despite the slot being considered Vacant for this entry, it might be occupied
        // with an outdated element.
        match replace(slot, Slot::new_occupied(self.kd.version.get(), value)) {
            Occupied { .. } => {},
            Vacant => self.map.num_elems += 1,
        }
        unsafe { slot.get_unchecked_mut() }
    }
}

// Iterators.
/// A draining iterator for [`SecondaryMap`].
///
/// This iterator is created by [`SecondaryMap::drain`].
#[derive(Debug)]
pub struct Drain<'a, K: Key + 'a, V: 'a> {
    sm: &'a mut SecondaryMap<K, V>,
    cur: usize,
}

/// An iterator that moves key-value pairs out of a [`SecondaryMap`].
///
/// This iterator is created by calling the `into_iter` method on [`SecondaryMap`],
/// provided by the [`IntoIterator`] trait.
#[derive(Debug)]
pub struct IntoIter<K: Key, V> {
    num_left: usize,
    slots: Enumerate<alloc::vec::IntoIter<Slot<V>>>,
    _k: PhantomData<fn(K) -> K>,
}

/// An iterator over the key-value pairs in a [`SecondaryMap`].
///
/// This iterator is created by [`SecondaryMap::iter`].
#[derive(Debug)]
pub struct Iter<'a, K: Key + 'a, V: 'a> {
    num_left: usize,
    slots: Enumerate<core::slice::Iter<'a, Slot<V>>>,
    _k: PhantomData<fn(K) -> K>,
}

impl<'a, K: 'a + Key, V: 'a> Clone for Iter<'a, K, V> {
    fn clone(&self) -> Self {
        Iter {
            num_left: self.num_left,
            slots: self.slots.clone(),
            _k: self._k,
        }
    }
}

/// A mutable iterator over the key-value pairs in a [`SecondaryMap`].
///
/// This iterator is created by [`SecondaryMap::iter_mut`].
#[derive(Debug)]
pub struct IterMut<'a, K: Key + 'a, V: 'a> {
    num_left: usize,
    slots: Enumerate<core::slice::IterMut<'a, Slot<V>>>,
    _k: PhantomData<fn(K) -> K>,
}

/// An iterator over the keys in a [`SecondaryMap`].
///
/// This iterator is created by [`SecondaryMap::keys`].
#[derive(Debug)]
pub struct Keys<'a, K: Key + 'a, V: 'a> {
    inner: Iter<'a, K, V>,
}

impl<'a, K: 'a + Key, V: 'a> Clone for Keys<'a, K, V> {
    fn clone(&self) -> Self {
        Keys {
            inner: self.inner.clone(),
        }
    }
}

/// An iterator over the values in a [`SecondaryMap`].
///
/// This iterator is created by [`SecondaryMap::values`].
#[derive(Debug)]
pub struct Values<'a, K: Key + 'a, V: 'a> {
    inner: Iter<'a, K, V>,
}

impl<'a, K: 'a + Key, V: 'a> Clone for Values<'a, K, V> {
    fn clone(&self) -> Self {
        Values {
            inner: self.inner.clone(),
        }
    }
}

/// A mutable iterator over the values in a [`SecondaryMap`].
///
/// This iterator is created by [`SecondaryMap::values_mut`].
#[derive(Debug)]
pub struct ValuesMut<'a, K: Key + 'a, V: 'a> {
    inner: IterMut<'a, K, V>,
}

impl<'a, K: Key, V> Iterator for Drain<'a, K, V> {
    type Item = (K, V);

    fn next(&mut self) -> Option<(K, V)> {
        while let Some(slot) = self.sm.slots.get_mut(self.cur) {
            let idx = self.cur;
            self.cur += 1;
            if let Occupied { value, version } = replace(slot, Slot::new_vacant()) {
                self.sm.num_elems -= 1;
                let key = KeyData::new(idx as u32, version.get()).into();
                return Some((key, value));
            }
        }

        None
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.sm.len(), Some(self.sm.len()))
    }
}

impl<'a, K: Key, V> Drop for Drain<'a, K, V> {
    fn drop(&mut self) {
        self.for_each(|_drop| {});
    }
}

impl<K: Key, V> Iterator for IntoIter<K, V> {
    type Item = (K, V);

    fn next(&mut self) -> Option<(K, V)> {
        while let Some((idx, mut slot)) = self.slots.next() {
            if let Occupied { value, version } = replace(&mut slot, Slot::new_vacant()) {
                self.num_left -= 1;
                let key = KeyData::new(idx as u32, version.get()).into();
                return Some((key, value));
            }
        }

        None
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.num_left, Some(self.num_left))
    }
}

impl<'a, K: Key, V> Iterator for Iter<'a, K, V> {
    type Item = (K, &'a V);

    fn next(&mut self) -> Option<(K, &'a V)> {
        while let Some((idx, slot)) = self.slots.next() {
            if let Occupied { value, version } = slot {
                self.num_left -= 1;
                let key = KeyData::new(idx as u32, version.get()).into();
                return Some((key, value));
            }
        }

        None
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.num_left, Some(self.num_left))
    }
}

impl<'a, K: Key, V> Iterator for IterMut<'a, K, V> {
    type Item = (K, &'a mut V);

    fn next(&mut self) -> Option<(K, &'a mut V)> {
        while let Some((idx, slot)) = self.slots.next() {
            if let Occupied { value, version } = slot {
                let key = KeyData::new(idx as u32, version.get()).into();
                self.num_left -= 1;
                return Some((key, value));
            }
        }

        None
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.num_left, Some(self.num_left))
    }
}

impl<'a, K: Key, V> Iterator for Keys<'a, K, V> {
    type Item = K;

    fn next(&mut self) -> Option<K> {
        self.inner.next().map(|(key, _)| key)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }
}

impl<'a, K: Key, V> Iterator for Values<'a, K, V> {
    type Item = &'a V;

    fn next(&mut self) -> Option<&'a V> {
        self.inner.next().map(|(_, value)| value)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }
}

impl<'a, K: Key, V> Iterator for ValuesMut<'a, K, V> {
    type Item = &'a mut V;

    fn next(&mut self) -> Option<&'a mut V> {
        self.inner.next().map(|(_, value)| value)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.inner.size_hint()
    }
}

impl<'a, K: Key, V> IntoIterator for &'a SecondaryMap<K, V> {
    type Item = (K, &'a V);
    type IntoIter = Iter<'a, K, V>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a, K: Key, V> IntoIterator for &'a mut SecondaryMap<K, V> {
    type Item = (K, &'a mut V);
    type IntoIter = IterMut<'a, K, V>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter_mut()
    }
}

impl<K: Key, V> IntoIterator for SecondaryMap<K, V> {
    type Item = (K, V);
    type IntoIter = IntoIter<K, V>;

    fn into_iter(self) -> Self::IntoIter {
        let len = self.len();
        let mut it = self.slots.into_iter().enumerate();
        it.next(); // Skip sentinel.
        IntoIter {
            num_left: len,
            slots: it,
            _k: PhantomData,
        }
    }
}

impl<'a, K: Key, V> FusedIterator for Iter<'a, K, V> {}
impl<'a, K: Key, V> FusedIterator for IterMut<'a, K, V> {}
impl<'a, K: Key, V> FusedIterator for Keys<'a, K, V> {}
impl<'a, K: Key, V> FusedIterator for Values<'a, K, V> {}
impl<'a, K: Key, V> FusedIterator for ValuesMut<'a, K, V> {}
impl<'a, K: Key, V> FusedIterator for Drain<'a, K, V> {}
impl<K: Key, V> FusedIterator for IntoIter<K, V> {}

impl<'a, K: Key, V> ExactSizeIterator for Iter<'a, K, V> {}
impl<'a, K: Key, V> ExactSizeIterator for IterMut<'a, K, V> {}
impl<'a, K: Key, V> ExactSizeIterator for Keys<'a, K, V> {}
impl<'a, K: Key, V> ExactSizeIterator for Values<'a, K, V> {}
impl<'a, K: Key, V> ExactSizeIterator for ValuesMut<'a, K, V> {}
impl<'a, K: Key, V> ExactSizeIterator for Drain<'a, K, V> {}
impl<K: Key, V> ExactSizeIterator for IntoIter<K, V> {}

// Serialization with serde.
#[cfg(feature = "serde")]
mod serialize {
    use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

    use super::*;

    #[derive(Serialize, Deserialize)]
    struct SerdeSlot<T> {
        value: Option<T>,
        version: u32,
    }

    impl<T: Serialize> Serialize for Slot<T> {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            let serde_slot = SerdeSlot {
                version: self.version(),
                value: match self {
                    Occupied { value, .. } => Some(value),
                    Vacant => None,
                },
            };
            serde_slot.serialize(serializer)
        }
    }

    impl<'de, T> Deserialize<'de> for Slot<T>
    where
        T: Deserialize<'de>,
    {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            let serde_slot: SerdeSlot<T> = Deserialize::deserialize(deserializer)?;
            let occupied = serde_slot.version % 2 == 1;
            if occupied ^ serde_slot.value.is_some() {
                return Err(de::Error::custom(&"inconsistent occupation in Slot"));
            }

            Ok(match serde_slot.value {
                Some(value) => Self::new_occupied(serde_slot.version, value),
                None => Self::new_vacant(),
            })
        }
    }

    impl<K: Key, V: Serialize> Serialize for SecondaryMap<K, V> {
        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            self.slots.serialize(serializer)
        }
    }

    impl<'de, K: Key, V: Deserialize<'de>> Deserialize<'de> for SecondaryMap<K, V> {
        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where
            D: Deserializer<'de>,
        {
            let mut slots: Vec<Slot<V>> = Deserialize::deserialize(deserializer)?;
            if slots.len() >= (u32::max_value() - 1) as usize {
                return Err(de::Error::custom(&"too many slots"));
            }

            // Ensure the first slot exists and is empty for the sentinel.
            if slots.get(0).map_or(true, |slot| slot.occupied()) {
                return Err(de::Error::custom(&"first slot not empty"));
            }

            slots[0] = Slot::new_vacant();
            let num_elems = slots.iter().map(|s| s.occupied() as usize).sum();

            Ok(Self {
                num_elems,
                slots,
                _k: PhantomData,
            })
        }
    }
}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use quickcheck::quickcheck;

    use crate::*;

    #[cfg(all(nightly, feature = "unstable"))]
    #[test]
    fn disjoint() {
        // Intended to be run with miri to find any potential UB.
        let mut sm = SlotMap::new();
        let mut sec = SecondaryMap::new();

        // Some churn.
        for i in 0..20usize {
            sm.insert(i);
        }
        sm.retain(|_, i| *i % 2 == 0);

        for (i, k) in sm.keys().enumerate() {
            sec.insert(k, i);
        }

        let keys: Vec<_> = sm.keys().collect();
        for i in 0..keys.len() {
            for j in 0..keys.len() {
                if let Some([r0, r1]) = sec.get_disjoint_mut([keys[i], keys[j]]) {
                    *r0 ^= *r1;
                    *r1 = r1.wrapping_add(*r0);
                } else {
                    assert!(i == j);
                }
            }
        }

        for i in 0..keys.len() {
            for j in 0..keys.len() {
                for k in 0..keys.len() {
                    if let Some([r0, r1, r2]) = sec.get_disjoint_mut([keys[i], keys[j], keys[k]]) {
                        *r0 ^= *r1;
                        *r0 = r0.wrapping_add(*r2);
                        *r1 ^= *r0;
                        *r1 = r1.wrapping_add(*r2);
                        *r2 ^= *r0;
                        *r2 = r2.wrapping_add(*r1);
                    } else {
                        assert!(i == j || j == k || i == k);
                    }
                }
            }
        }
    }

    quickcheck! {
        fn qc_secmap_equiv_hashmap(operations: Vec<(u8, u32)>) -> bool {
            let mut hm = HashMap::new();
            let mut hm_keys = Vec::new();
            let mut unique_key = 0u32;
            let mut sm = SlotMap::new();
            let mut sec = SecondaryMap::new();
            let mut sm_keys = Vec::new();

            #[cfg(not(feature = "serde"))]
            let num_ops = 4;
            #[cfg(feature = "serde")]
            let num_ops = 5;

            for (op, val) in operations {
                match op % num_ops {
                    // Insert.
                    0 => {
                        hm.insert(unique_key, val);
                        hm_keys.push(unique_key);
                        unique_key += 1;

                        let k = sm.insert(val);
                        sec.insert(k, val);
                        sm_keys.push(k);
                    }

                    // Delete.
                    1 => {
                        if hm_keys.is_empty() { continue; }

                        let idx = val as usize % hm_keys.len();
                        sm.remove(sm_keys[idx]);
                        if hm.remove(&hm_keys[idx]) != sec.remove(sm_keys[idx]) {
                            return false;
                        }
                    }

                    // Access.
                    2 => {
                        if hm_keys.is_empty() { continue; }
                        let idx = val as usize % hm_keys.len();
                        let (hm_key, sm_key) = (&hm_keys[idx], sm_keys[idx]);

                        if hm.contains_key(hm_key) != sec.contains_key(sm_key) ||
                           hm.get(hm_key) != sec.get(sm_key) {
                            return false;
                        }
                    }

                    // Clone.
                    3 => {
                        sec = sec.clone();
                    }

                    // Serde round-trip.
                    #[cfg(feature = "serde")]
                    4 => {
                        let ser = serde_json::to_string(&sec).unwrap();
                        sec = serde_json::from_str(&ser).unwrap();
                    }

                    _ => unreachable!(),
                }
            }

            let mut secv: Vec<_> = sec.values().collect();
            let mut hmv: Vec<_> = hm.values().collect();
            secv.sort();
            hmv.sort();
            secv == hmv
        }
    }
}
