use std::fmt::{Display, Formatter};
use std::hash::Hash;
use std::ptr::NonNull;
use std::rc::Rc;
use super::Node;
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub(super) struct LfuEntry<Key: Hash + Eq, Value> {
pub(super) next: Option<NonNull<Self>>,
pub(super) prev: Option<NonNull<Self>>,
pub(super) owner: NonNull<Node<Key, Value>>,
pub(super) key: Rc<Key>,
pub(super) value: Value,
}
#[cfg(not(tarpaulin_include))]
impl<Key: Hash + Eq, Value: Display> Display for LfuEntry<Key, Value> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.value)
}
}
impl<Key: Hash + Eq, Value> LfuEntry<Key, Value> {
pub(super) fn detach_owned(node: NonNull<Self>) -> Detached<Key, Value> {
std::mem::forget(Self::detach(node));
let detached = unsafe { Box::from_raw(node.as_ptr()) };
Detached {
key: detached.key,
value: detached.value,
}
}
pub(super) fn detach(mut node: NonNull<Self>) -> DetachedRef<Key, Value> {
let node_ref = unsafe { node.as_mut() };
if let Some(mut prev) = node_ref.prev {
unsafe { prev.as_mut().next = node_ref.next };
}
if let Some(mut next) = node_ref.next {
unsafe { next.as_mut().prev = node_ref.prev };
}
node_ref.next = None;
node_ref.prev = None;
node_ref.owner = NonNull::dangling();
DetachedRef(node)
}
}
#[must_use]
pub struct DetachedRef<Key: Hash + Eq, Value>(NonNull<LfuEntry<Key, Value>>);
impl<Key: Hash + Eq, Value> Drop for DetachedRef<Key, Value> {
fn drop(&mut self) {
panic!("Detached reference was dropped. You should re-attach it or use std::mem::forget");
}
}
impl<Key: Hash + Eq, Value> DetachedRef<Key, Value> {
pub(super) fn attach_ref(
self,
prev: Option<NonNull<LfuEntry<Key, Value>>>,
next: Option<NonNull<LfuEntry<Key, Value>>>,
owner: NonNull<Node<Key, Value>>,
) -> NonNull<LfuEntry<Key, Value>> {
let mut node = self.0;
let node_ref = unsafe { node.as_mut() };
node_ref.next = next; node_ref.prev = prev; node_ref.owner = owner;
if let Some(mut prev) = unsafe { node.as_mut() }.prev {
unsafe { prev.as_mut() }.next = Some(node);
}
if let Some(mut next) = unsafe { node.as_mut() }.next {
unsafe { next.as_mut() }.prev = Some(node);
}
std::mem::forget(self);
node
}
}
#[must_use]
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone)]
pub(super) struct Detached<Key, Value> {
pub(super) key: Rc<Key>,
pub(super) value: Value,
}
impl<Key: Hash + Eq, Value> Detached<Key, Value> {
pub fn new(key: Rc<Key>, value: Value) -> Self {
Self { key, value }
}
pub fn attach(
self,
prev: Option<NonNull<LfuEntry<Key, Value>>>,
next: Option<NonNull<LfuEntry<Key, Value>>>,
owner: NonNull<Node<Key, Value>>,
) -> NonNull<LfuEntry<Key, Value>> {
let new_node = LfuEntry {
next, prev, owner, key: self.key,
value: self.value,
};
let leaked = Box::leak(Box::new(new_node));
let mut non_null = NonNull::from(leaked);
if let Some(mut next) = unsafe { non_null.as_mut() }.next {
unsafe { next.as_mut() }.prev = Some(non_null);
}
if let Some(mut prev) = unsafe { non_null.as_mut() }.prev {
unsafe { prev.as_mut() }.next = Some(non_null);
}
non_null
}
}