non-empty-collections 0.1.9

Non-empty hash-map and hash-set implementations
Documentation
use super::Index;
use std::hash::{BuildHasher, Hash};
use std::mem;
use std::ops::{Deref, DerefMut};
use {Error, NonEmptyIndexMap};

/// An occupied entry.
pub struct Occupied<'a, K: 'a, V: 'a, S: 'a> {
    pub(super) key: K,
    pub(super) index: Index,
    pub(super) map: &'a mut NonEmptyIndexMap<K, V, S>,
}

/// A vacant (empty) entry.
pub struct Vacant<'a, K: 'a, V: 'a, S: 'a> {
    pub(super) key: K,
    pub(super) map: &'a mut NonEmptyIndexMap<K, V, S>,
}

/// A map's entry.
pub enum Entry<'a, K: 'a, V: 'a, S: 'a> {
    /// An occupied entry.
    Occupied(Occupied<'a, K, V, S>),
    /// A vacant (empty) entry.
    Vacant(Vacant<'a, K, V, S>),
}

impl<'a, K: 'a, V: 'a, S: 'a> Deref for Occupied<'a, K, V, S>
where
    K: Eq + Hash,
    S: BuildHasher,
{
    type Target = V;

    fn deref(&self) -> &V {
        self.map.get_entry(self.index)
    }
}

impl<'a, K: 'a, V: 'a, S: 'a> DerefMut for Occupied<'a, K, V, S>
where
    K: Eq + Hash,
    S: BuildHasher,
{
    fn deref_mut(&mut self) -> &mut V {
        self.map.get_entry_mut(self.index)
    }
}

impl<'a, K: 'a, V: 'a, S: 'a> Occupied<'a, K, V, S>
where
    K: Eq + Hash,
    S: BuildHasher,
{
    /// Removes the entry from the map.
    ///
    /// Will fail on an attempt to remove the last element from the map.
    pub fn remove_entry(self) -> Result<(K, V), Error> {
        let key = self.key;
        let map = self.map;
        map.remove_entry(&key)
            .map(|x| x.expect("The entry exists for sure"))
    }

    /// Replace the entry's value with a given one, returning the old one.
    pub fn replace(&mut self, new_value: V) -> V {
        let old = self.map.get_entry_mut(self.index);
        mem::replace(old, new_value)
    }

    pub fn into_value(self) -> &'a mut V {
        let idx = self.index;
        self.map.get_entry_mut(idx)
    }
}

impl<'a, K: 'a, V: 'a, S: 'a> Vacant<'a, K, V, S>
where
    K: Eq + Hash,
    S: BuildHasher,
{
    pub fn insert(self, value: V) -> &'a mut V {
        let map = self.map;
        let key = self.key;
        match map.get_rest_mut().entry(key) {
            ::indexmap::map::Entry::Occupied(_) => panic!("The entry exists for sure"),
            ::indexmap::map::Entry::Vacant(entry) => entry.insert(value),
        }
    }
}

impl<'a, K: 'a, V: 'a, S: 'a> Entry<'a, K, V, S>
where
    K: Eq + Hash,
    S: BuildHasher,
{
    /// Returns a mutable reference to a value if the entry exists, or creates a new entry using a
    /// given closure if it doesn't exist yet and returns a reference to a newly created entry's
    /// value.
    pub fn or_insert(self, value: V) -> &'a mut V {
        match self {
            Entry::Occupied(x) => x.into_value(),
            Entry::Vacant(v) => v.insert(value),
        }
    }

    /// Returns a mutable reference to a value if the entry exists, or creates a new entry with a
    /// given value if it doesn't exist yet and returns a reference to a newly created entry's
    /// value.
    pub fn or_insert_with<F>(self, f: F) -> &'a mut V
    where
        F: FnOnce() -> V,
    {
        match self {
            Entry::Occupied(x) => x.into_value(),
            Entry::Vacant(v) => v.insert(f()),
        }
    }
}

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

    #[test]
    fn test_occupied_one() {
        let mut map = NonEmptyIndexMap::new(1, 2);
        let entry = map.entry(1);
        let occupied = match entry {
            Entry::Occupied(x) => x,
            Entry::Vacant(_) => panic!("Expected an occupied entry"),
        };
        assert_eq!(Err(Error::EmptyCollection), occupied.remove_entry());
    }

    #[test]
    fn test_occupied() {
        let mut map = NonEmptyIndexMap::from_item_and_iterator(1, 2, vec![(3, 4), (5, 6), (7, 8)]);
        {
            let entry = map.entry(1);
            let occupied = match entry {
                Entry::Occupied(x) => x,
                Entry::Vacant(_) => panic!("Expected an occupied entry"),
            };
            assert_eq!(Ok((1, 2)), occupied.remove_entry());
        }
        assert_eq!(3, map.len());
        {
            let entry = map.entry(5);
            match entry {
                Entry::Occupied(x) => x,
                Entry::Vacant(_) => panic!("Expected an occupied entry"),
            };
        }
        assert_eq!(3, map.len());
    }

    #[test]
    fn test_vacant() {
        let mut map = NonEmptyIndexMap::new(1, 2);
        {
            let entry = map.entry(2);
            let vacant = match entry {
                Entry::Vacant(x) => x,
                Entry::Occupied(_) => panic!("Expected a vacant entry"),
            };
            assert_eq!(&3, vacant.insert(3));
        }
        assert_eq!(Some(&3), map.get(&2));
    }

    #[test]
    fn test_or_insert() {
        let mut map = NonEmptyIndexMap::new(1, 2);
        {
            let entry = map.entry(1);
            assert_eq!(&2, entry.or_insert(3));
        }
        assert_eq!(Some(&2), map.get(&1));
        assert_eq!(1, map.len());
        {
            let entry = map.entry(2);
            assert_eq!(&3, entry.or_insert(3));
        }
        assert_eq!(Some(&3), map.get(&2));
        assert_eq!(2, map.len());
    }

    #[test]
    fn test_or_insert_with() {
        let mut map = NonEmptyIndexMap::new(1, 2);
        {
            let entry = map.entry(1);
            assert_eq!(&2, entry.or_insert_with(|| 3));
        }
        assert_eq!(Some(&2), map.get(&1));
        assert_eq!(1, map.len());
        {
            let entry = map.entry(2);
            assert_eq!(&3, entry.or_insert_with(|| 3));
        }
        assert_eq!(Some(&3), map.get(&2));
        assert_eq!(2, map.len());
    }
}