use crate::inner::{Core, OccupiedEntry, VacantEntry}; use crate::Bucket; use core::{fmt, mem}; /// Entry for an existing key-value pair in an [`IndexMap`][crate::IndexMap] /// or a vacant location to insert one. pub enum Entry<'a, K, V> { /// Existing slot with equivalent key. Occupied(OccupiedEntry<'a, K, V>), /// Vacant slot (no equivalent key in the map). Vacant(VacantEntry<'a, K, V>), } impl<'a, K, V> Entry<'a, K, V> { /// Return the index where the key-value pair exists or will be inserted. pub fn index(&self) -> usize { match self { Entry::Occupied(entry) => entry.index(), Entry::Vacant(entry) => entry.index(), } } /// Sets the value of the entry (after inserting if vacant), and returns an `OccupiedEntry`. /// /// Computes in **O(1)** time (amortized average). pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V> { match self { Entry::Occupied(mut entry) => { entry.insert(value); entry } Entry::Vacant(entry) => entry.insert_entry(value), } } /// Inserts the given default value in the entry if it is vacant and returns a mutable /// reference to it. Otherwise a mutable reference to an already existent value is returned. /// /// Computes in **O(1)** time (amortized average). pub fn or_insert(self, default: V) -> &'a mut V { match self { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => entry.insert(default), } } /// Inserts the result of the `call` function in the entry if it is vacant and returns a mutable /// reference to it. Otherwise a mutable reference to an already existent value is returned. /// /// Computes in **O(1)** time (amortized average). pub fn or_insert_with(self, call: F) -> &'a mut V where F: FnOnce() -> V, { match self { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => entry.insert(call()), } } /// Inserts the result of the `call` function with a reference to the entry's key if it is /// vacant, and returns a mutable reference to the new value. Otherwise a mutable reference to /// an already existent value is returned. /// /// Computes in **O(1)** time (amortized average). pub fn or_insert_with_key(self, call: F) -> &'a mut V where F: FnOnce(&K) -> V, { match self { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => { let value = call(entry.key()); entry.insert(value) } } } /// Gets a reference to the entry's key, either within the map if occupied, /// or else the new key that was used to find the entry. pub fn key(&self) -> &K { match *self { Entry::Occupied(ref entry) => entry.key(), Entry::Vacant(ref entry) => entry.key(), } } /// Modifies the entry if it is occupied. pub fn and_modify(mut self, f: F) -> Self where F: FnOnce(&mut V), { if let Entry::Occupied(entry) = &mut self { f(entry.get_mut()); } self } /// Inserts a default-constructed value in the entry if it is vacant and returns a mutable /// reference to it. Otherwise a mutable reference to an already existent value is returned. /// /// Computes in **O(1)** time (amortized average). pub fn or_default(self) -> &'a mut V where V: Default, { match self { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => entry.insert(V::default()), } } } impl fmt::Debug for Entry<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut tuple = f.debug_tuple("Entry"); match self { Entry::Vacant(v) => tuple.field(v), Entry::Occupied(o) => tuple.field(o), }; tuple.finish() } } impl fmt::Debug for OccupiedEntry<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("key", self.key()) .field("value", self.get()) .finish() } } impl fmt::Debug for VacantEntry<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.key()).finish() } } /// A view into an occupied entry in an [`IndexMap`][crate::IndexMap] obtained by index. /// /// This `struct` is created from the [`get_index_entry`][crate::IndexMap::get_index_entry] method. pub struct IndexedEntry<'a, K, V> { map: &'a mut Core, // We have a mutable reference to the map, which keeps the index // valid and pointing to the correct entry. index: usize, } impl<'a, K, V> IndexedEntry<'a, K, V> { pub(crate) fn new(map: &'a mut Core, index: usize) -> Option { if index < map.len() { Some(Self { map, index }) } else { None } } /// Return the index of the key-value pair #[inline] pub fn index(&self) -> usize { self.index } pub(crate) fn into_core(self) -> &'a mut Core { self.map } fn get_bucket(&self) -> &Bucket { &self.map.as_entries()[self.index] } fn get_bucket_mut(&mut self) -> &mut Bucket { &mut self.map.as_entries_mut()[self.index] } fn into_bucket(self) -> &'a mut Bucket { &mut self.map.as_entries_mut()[self.index] } /// Gets a reference to the entry's key in the map. pub fn key(&self) -> &K { &self.get_bucket().key } pub(super) fn key_mut(&mut self) -> &mut K { &mut self.get_bucket_mut().key } /// Gets a reference to the entry's value in the map. pub fn get(&self) -> &V { &self.get_bucket().value } /// Gets a mutable reference to the entry's value in the map. /// /// If you need a reference which may outlive the destruction of the /// `IndexedEntry` value, see [`into_mut`][Self::into_mut]. pub fn get_mut(&mut self) -> &mut V { &mut self.get_bucket_mut().value } /// Sets the value of the entry to `value`, and returns the entry's old value. pub fn insert(&mut self, value: V) -> V { mem::replace(self.get_mut(), value) } /// Converts into a mutable reference to the entry's value in the map, /// with a lifetime bound to the map itself. pub fn into_mut(self) -> &'a mut V { &mut self.into_bucket().value } /// Remove and return the key, value pair stored in the map for this entry /// /// Like [`Vec::swap_remove`][alloc::vec::Vec::swap_remove], the pair is removed by swapping it /// with the last element of the map and popping it off. /// **This perturbs the position of what used to be the last element!** /// /// Computes in **O(1)** time (average). pub fn swap_remove_entry(self) -> (K, V) { self.map.swap_remove_index(self.index).unwrap() } /// Remove and return the key, value pair stored in the map for this entry /// /// Like [`Vec::remove`][alloc::vec::Vec::remove], the pair is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// /// Computes in **O(n)** time (average). pub fn shift_remove_entry(self) -> (K, V) { self.map.shift_remove_index(self.index).unwrap() } /// Remove the key, value pair stored in the map for this entry, and return the value. /// /// Like [`Vec::swap_remove`][alloc::vec::Vec::swap_remove], the pair is removed by swapping it /// with the last element of the map and popping it off. /// **This perturbs the position of what used to be the last element!** /// /// Computes in **O(1)** time (average). pub fn swap_remove(self) -> V { self.swap_remove_entry().1 } /// Remove the key, value pair stored in the map for this entry, and return the value. /// /// Like [`Vec::remove`][alloc::vec::Vec::remove], the pair is removed by shifting all of the /// elements that follow it, preserving their relative order. /// **This perturbs the index of all of those elements!** /// /// Computes in **O(n)** time (average). pub fn shift_remove(self) -> V { self.shift_remove_entry().1 } /// Moves the position of the entry to a new index /// by shifting all other entries in-between. /// /// This is equivalent to [`IndexMap::move_index`][`crate::IndexMap::move_index`] /// coming `from` the current [`.index()`][Self::index]. /// /// * If `self.index() < to`, the other pairs will shift down while the targeted pair moves up. /// * If `self.index() > to`, the other pairs will shift up while the targeted pair moves down. /// /// ***Panics*** if `to` is out of bounds. /// /// Computes in **O(n)** time (average). #[track_caller] pub fn move_index(self, to: usize) { self.map.move_index(self.index, to); } /// Swaps the position of entry with another. /// /// This is equivalent to [`IndexMap::swap_indices`][`crate::IndexMap::swap_indices`] /// with the current [`.index()`][Self::index] as one of the two being swapped. /// /// ***Panics*** if the `other` index is out of bounds. /// /// Computes in **O(1)** time (average). #[track_caller] pub fn swap_indices(self, other: usize) { self.map.swap_indices(self.index, other); } } impl fmt::Debug for IndexedEntry<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("IndexedEntry") .field("index", &self.index) .field("key", self.key()) .field("value", self.get()) .finish() } } impl<'a, K, V> From> for IndexedEntry<'a, K, V> { fn from(other: OccupiedEntry<'a, K, V>) -> Self { Self { index: other.index(), map: other.into_core(), } } } #[test] fn assert_send_sync() { fn assert_send_sync() {} assert_send_sync::>(); assert_send_sync::>(); }