]> git.lizzy.rs Git - rust.git/blobdiff - src/mono_hash_map.rs
Auto merge of #2427 - Nilstrieb:doc-fix, r=saethlin
[rust.git] / src / mono_hash_map.rs
index fb0169920ee28fedc71d6b8882935c8429797cd1..45057632df9b528274b767cbc76c4f87a8eeeb52 100644 (file)
@@ -61,7 +61,7 @@ fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
 
     #[inline(always)]
     fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
-        self.0.borrow().iter().filter_map(move |(k, v)| f(k, &*v)).collect()
+        self.0.borrow().iter().filter_map(move |(k, v)| f(k, v)).collect()
     }
 
     /// The most interesting method: Providing a shared reference without
@@ -72,15 +72,31 @@ fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T
     /// returns owned data, that is put into the map and returned.
     #[inline(always)]
     fn get_or<E>(&self, k: K, vacant: impl FnOnce() -> Result<V, E>) -> Result<&V, E> {
-        let val: *const V = match self.0.borrow_mut().entry(k) {
-            Entry::Occupied(entry) => &**entry.get(),
-            Entry::Vacant(entry) => &**entry.insert(Box::new(vacant()?)),
-        };
+        // We cannot hold borrow_mut while calling `vacant`, since that might have to do lookups in this very map.
+        if let Some(v) = self.0.borrow().get(&k) {
+            let val: *const V = &**v;
+            // This is safe because `val` points into a `Box`, that we know will not move and
+            // will also not be dropped as long as the shared reference `self` is live.
+            return unsafe { Ok(&*val) };
+        }
+        let new_val = Box::new(vacant()?);
+        let val: *const V = &**self.0.borrow_mut().try_insert(k, new_val).ok().unwrap();
         // This is safe because `val` points into a `Box`, that we know will not move and
         // will also not be dropped as long as the shared reference `self` is live.
         unsafe { Ok(&*val) }
     }
 
+    /// Read-only lookup (avoid read-acquiring the RefCell).
+    fn get(&self, k: K) -> Option<&V> {
+        let val: *const V = match self.0.borrow().get(&k) {
+            Some(v) => &**v,
+            None => return None,
+        };
+        // This is safe because `val` points into a `Box`, that we know will not move and
+        // will also not be dropped as long as the shared reference `self` is live.
+        unsafe { Some(&*val) }
+    }
+
     #[inline(always)]
     fn get_mut_or<E>(&mut self, k: K, vacant: impl FnOnce() -> Result<V, E>) -> Result<&mut V, E> {
         match self.0.get_mut().entry(k) {