add drop impl
This commit is contained in:
@@ -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;
|
||||
|
Reference in New Issue
Block a user