add drop impl

This commit is contained in:
2025-07-19 23:26:22 +02:00
parent 50b35de725
commit 0d8780017b
3 changed files with 51 additions and 19 deletions

View File

@@ -2,7 +2,7 @@
//!
//! Doubly as each node points to the next and previous node.
use std::ops::Deref;
use std::{mem::transmute, ops::Deref, pin::Pin};
use parking_lot::RwLock;
@@ -26,17 +26,20 @@ impl<T> Default for NodeHeadInner<'_, T> {
}
}
// TODO:
// impl<'ll, T> Drop for LinkedList<'ll, T> {
// fn drop(&mut self) {
// // SAFETY: this is the very last ref of &self so it can pretty much assume no external
// // refs into the inner data as they would be invalid to live after this
// while unsafe { self.pop().is_some() } {}
// }
// }
pub struct LinkedList<'ll, T>(RwLock<NodeHeadInner<'ll, T>>);
impl<'ll, T> Drop for LinkedList<'ll, T> {
fn drop(&mut self) {
// SAFETY: this is the drop impl so we can guarantee the reference is valid for the
// lifetime of the struct itself and external references would be invalidated right after
// the [`Drop`] of it (this fn). I don't think there's a way to differenciate the lifetimes
// by a drop implementation so this would be safe as no external references lifetimes would
// be valid after drop finishes
let myself = unsafe { transmute::<&mut Self, &'ll mut Self>(self) };
while unsafe { myself.pop().is_some() } {}
}
}
impl<T> Default for LinkedList<'_, T> {
#[must_use]
fn default() -> Self {
@@ -58,6 +61,30 @@ impl<'ll, T> LinkedList<'ll, T> {
Self::default()
}
/// # Safety
///
/// The only context in which it's safe to call this when [`self`] was pinned immediately after
/// its creation so that it can be guaranteed that the returned reference is valid for all the
/// [`LinkedList`]'s lifetime.
///
/// The issue arises from the [`Drop`] implementation. It takes a `&mut` reference, that means
/// that all previous immutable references are dropped. But most methods of the linked require
/// you to promise the borrow of [`self`] is valid for all `'ll` and that's only true if no
/// destructor runs. This makes [`Drop`] incompatible with the use of methods of the form
/// `fn(&'myself self)`.
///
/// In turn to this, the [`Drop`] implementation must assume it's not the only reference even
/// thought it's `&mut`. Anyhow it should only be called when the scope of [`self`] is about to
/// end and the other references would be invalidated after the call to [`Drop`], though in
/// reality they really have no use before that call but to guarantee the "internal" self
/// references in the linked list remain valid through the destructor. It's kinda a really edge
/// case in the language with shared structures that require references with lifetimes as long
/// as self to guarantee their validity but still have [`Drop`] implementations.
#[must_use]
pub unsafe fn get_self_ref(myself: Pin<&Self>) -> &'ll Self {
unsafe { transmute::<&Self, &'ll Self>(myself.get_ref()) }
}
pub fn prepend(&'ll self, data: T) {
let self_lock = self.write();
let next = self_lock.start;