diff --git a/src/lib.rs b/src/lib.rs index 8f3ff25..0a96da6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -74,7 +74,7 @@ use core::iter::FusedIterator; use core::marker::PhantomData; use core::mem; use core::num::NonZeroUsize; -use core::ptr; +use core::ptr::{self, NonNull}; use core::usize; #[cfg(any(test, not(feature = "hashbrown")))] @@ -189,7 +189,7 @@ pub type DefaultHasher = std::collections::hash_map::RandomState; /// An LRU Cache pub struct LruCache { - map: HashMap, *mut LruEntry, S>, + map: HashMap, NonNull>, S>, cap: NonZeroUsize, // head and tail are sigil nodes to facilitate inserting entries @@ -266,7 +266,7 @@ impl LruCache { /// Creates a new LRU Cache with the given capacity. fn construct( cap: NonZeroUsize, - map: HashMap, *mut LruEntry, S>, + map: HashMap, NonNull>, S>, ) -> LruCache { // NB: The compiler warns that cache does not need to be marked as mutable if we // declare it as such since we only mutate it inside the unsafe block. @@ -342,21 +342,22 @@ impl LruCache { match node_ref { Some(node_ref) => { - let node_ptr: *mut LruEntry = *node_ref; + let node_ptr: *mut LruEntry = node_ref.as_ptr(); // if the key is already in the cache just update its value and move it to the // front of the list - unsafe { mem::swap(&mut v, &mut (*(*node_ptr).val.as_mut_ptr()) as &mut V) } + unsafe { mem::swap(&mut v, &mut *(*node_ptr).val.as_mut_ptr()) } self.detach(node_ptr); self.attach(node_ptr); Some((k, v)) } None => { let (replaced, node) = self.replace_or_create_node(k, v); + let node_ptr: *mut LruEntry = node.as_ptr(); - self.attach(node); + self.attach(node_ptr); - let keyref = unsafe { (*node).key.as_ptr() }; + let keyref = unsafe { (*node_ptr).key.as_ptr() }; self.map.insert(KeyRef { k: keyref }, node); replaced.filter(|_| capture) @@ -367,29 +368,32 @@ impl LruCache { // Used internally to swap out a node if the cache is full or to create a new node if space // is available. Shared between `put`, `push`, `get_or_insert`, and `get_or_insert_mut`. #[allow(clippy::type_complexity)] - fn replace_or_create_node(&mut self, k: K, v: V) -> (Option<(K, V)>, *mut LruEntry) { + fn replace_or_create_node(&mut self, k: K, v: V) -> (Option<(K, V)>, NonNull>) { if self.len() == self.cap().get() { // if the cache is full, remove the last entry so we can use it for the new key let old_key = KeyRef { k: unsafe { &(*(*(*self.tail).prev).key.as_ptr()) }, }; let old_node = self.map.remove(&old_key).unwrap(); + let node_ptr: *mut LruEntry = old_node.as_ptr(); // read out the node's old key and value and then replace it let replaced = unsafe { ( - mem::replace(&mut (*old_node).key, mem::MaybeUninit::new(k)).assume_init(), - mem::replace(&mut (*old_node).val, mem::MaybeUninit::new(v)).assume_init(), + mem::replace(&mut (*node_ptr).key, mem::MaybeUninit::new(k)).assume_init(), + mem::replace(&mut (*node_ptr).val, mem::MaybeUninit::new(v)).assume_init(), ) }; - let node_ptr: *mut LruEntry = old_node; self.detach(node_ptr); (Some(replaced), old_node) } else { // if the cache is not full allocate a new LruEntry - (None, Box::into_raw(Box::new(LruEntry::new(k, v)))) + // Safety: We allocate, turn into raw, and get NonNull all in one step. + (None, unsafe { + NonNull::new_unchecked(Box::into_raw(Box::new(LruEntry::new(k, v)))) + }) } } @@ -418,12 +422,12 @@ impl LruCache { Q: Hash + Eq + ?Sized, { if let Some(node) = self.map.get_mut(k) { - let node_ptr: *mut LruEntry = *node; + let node_ptr: *mut LruEntry = node.as_ptr(); self.detach(node_ptr); self.attach(node_ptr); - Some(unsafe { &(*(*node_ptr).val.as_ptr()) as &V }) + Some(unsafe { &*(*node_ptr).val.as_ptr() }) } else { None } @@ -454,12 +458,12 @@ impl LruCache { Q: Hash + Eq + ?Sized, { if let Some(node) = self.map.get_mut(k) { - let node_ptr: *mut LruEntry = *node; + let node_ptr: *mut LruEntry = node.as_ptr(); self.detach(node_ptr); self.attach(node_ptr); - Some(unsafe { &mut (*(*node_ptr).val.as_mut_ptr()) as &mut V }) + Some(unsafe { &mut *(*node_ptr).val.as_mut_ptr() }) } else { None } @@ -492,21 +496,22 @@ impl LruCache { F: FnOnce() -> V, { if let Some(node) = self.map.get_mut(&KeyRef { k: &k }) { - let node_ptr: *mut LruEntry = *node; + let node_ptr: *mut LruEntry = node.as_ptr(); self.detach(node_ptr); self.attach(node_ptr); - unsafe { &(*(*node_ptr).val.as_ptr()) as &V } + unsafe { &*(*node_ptr).val.as_ptr() } } else { let v = f(); let (_, node) = self.replace_or_create_node(k, v); + let node_ptr: *mut LruEntry = node.as_ptr(); - self.attach(node); + self.attach(node_ptr); - let keyref = unsafe { (*node).key.as_ptr() }; + let keyref = unsafe { (*node_ptr).key.as_ptr() }; self.map.insert(KeyRef { k: keyref }, node); - unsafe { &(*(*node).val.as_ptr()) as &V } + unsafe { &*(*node_ptr).val.as_ptr() } } } @@ -537,21 +542,22 @@ impl LruCache { F: FnOnce() -> V, { if let Some(node) = self.map.get_mut(&KeyRef { k: &k }) { - let node_ptr: *mut LruEntry = *node; + let node_ptr: *mut LruEntry = node.as_ptr(); self.detach(node_ptr); self.attach(node_ptr); - unsafe { &mut (*(*node_ptr).val.as_mut_ptr()) as &mut V } + unsafe { &mut *(*node_ptr).val.as_mut_ptr() } } else { let v = f(); let (_, node) = self.replace_or_create_node(k, v); + let node_ptr: *mut LruEntry = node.as_ptr(); - self.attach(node); + self.attach(node_ptr); - let keyref = unsafe { (*node).key.as_ptr() }; + let keyref = unsafe { (*node_ptr).key.as_ptr() }; self.map.insert(KeyRef { k: keyref }, node); - unsafe { &mut (*(*node).val.as_mut_ptr()) as &mut V } + unsafe { &mut *(*node_ptr).val.as_mut_ptr() } } } @@ -579,7 +585,7 @@ impl LruCache { { self.map .get(k) - .map(|node| unsafe { &(*(**node).val.as_ptr()) as &V }) + .map(|node| unsafe { &*node.as_ref().val.as_ptr() }) } /// Returns a mutable reference to the value corresponding to the key in the cache or `None` @@ -606,7 +612,7 @@ impl LruCache { { match self.map.get_mut(k) { None => None, - Some(node) => Some(unsafe { &mut (*(**node).val.as_mut_ptr()) as &mut V }), + Some(node) => Some(unsafe { &mut *(*node.as_ptr()).val.as_mut_ptr() }), } } @@ -693,7 +699,7 @@ impl LruCache { None => None, Some(old_node) => { let mut old_node = unsafe { - let mut old_node = *Box::from_raw(old_node); + let mut old_node = *Box::from_raw(old_node.as_ptr()); ptr::drop_in_place(old_node.key.as_mut_ptr()); old_node @@ -734,7 +740,7 @@ impl LruCache { match self.map.remove(k) { None => None, Some(old_node) => { - let mut old_node = unsafe { *Box::from_raw(old_node) }; + let mut old_node = unsafe { *Box::from_raw(old_node.as_ptr()) }; self.detach(&mut old_node); @@ -800,7 +806,7 @@ impl LruCache { Q: Hash + Eq + ?Sized, { if let Some(node) = self.map.get_mut(k) { - let node_ptr: *mut LruEntry = *node; + let node_ptr: *mut LruEntry = node.as_ptr(); self.detach(node_ptr); self.attach(node_ptr); } @@ -836,7 +842,7 @@ impl LruCache { Q: Hash + Eq + ?Sized, { if let Some(node) = self.map.get_mut(k) { - let node_ptr: *mut LruEntry = *node; + let node_ptr: *mut LruEntry = node.as_ptr(); self.detach(node_ptr); self.attach_last(node_ptr); } @@ -1026,9 +1032,9 @@ impl LruCache { k: unsafe { &(*(*(*self.tail).prev).key.as_ptr()) }, }; let old_node = self.map.remove(&old_key).unwrap(); - let node_ptr: *mut LruEntry = old_node; + let node_ptr: *mut LruEntry = old_node.as_ptr(); self.detach(node_ptr); - unsafe { Some(Box::from_raw(old_node)) } + unsafe { Some(Box::from_raw(node_ptr)) } } else { None } @@ -1065,7 +1071,7 @@ impl LruCache { impl Drop for LruCache { fn drop(&mut self) { self.map.drain().for_each(|(_, node)| unsafe { - let mut node = *Box::from_raw(node); + let mut node = *Box::from_raw(node.as_ptr()); ptr::drop_in_place((node).key.as_mut_ptr()); ptr::drop_in_place((node).val.as_mut_ptr()); });