//! Doubly non-Arc linked list. //! //! Doubly as each node points to the next and previous node. use std::{marker::PhantomPinned, mem::transmute, ops::Deref, pin::Pin}; use parking_lot::RwLock; use crate::double::node::{BackNodeWriteLock, Node, NodeBackPtr}; pub mod node; // # Rules to prevent deadlocks // // Left locking must be `try_` and if it fails at any point, the way rightwards must be cleared in // case the task holding the left lock is moving rightwards. // Rightwards locking can be blocking. pub struct NodeHeadInner<'ll, T> { start: Option<&'ll node::Node<'ll, T>>, } impl Default for NodeHeadInner<'_, T> { fn default() -> Self { Self { start: None } } } pub struct NodeHead<'ll, T>(RwLock>); impl Default for NodeHead<'_, T> { #[must_use] fn default() -> Self { Self(RwLock::new(NodeHeadInner::default())) } } impl<'ll, T> Deref for NodeHead<'ll, T> { type Target = RwLock>; fn deref(&self) -> &Self::Target { &self.0 } } impl<'ll, T> NodeHead<'ll, T> { #[must_use] pub fn new() -> Self { 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()) } } /// # Safety /// /// Must be at the end at the end of its scope, when there's no references into it left. pub unsafe fn manual_drop(&'ll 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 while unsafe { self.pop().is_some() } {} } pub fn prepend(&'ll self, data: T) { let self_lock = self.write(); let next = self_lock.start; let next_lock = next.map(|n| n.write()); let new_node = Node::new_leaked(data, NodeBackPtr::new_head(self), next); // SAFETY: ptrs are surrounding and they've been locked all along unsafe { new_node.integrate((BackNodeWriteLock::Head(self_lock), next_lock)) }; } /// Returns [`None`] if there's no next node. /// /// # Safety /// /// There must be no outer references to the first node. pub unsafe fn pop(&'ll self) -> Option<()> { let self_lock = self.write(); let pop_node = self_lock.start?; let pop_node_lock = pop_node.write(); let next_node_lock = pop_node_lock.next.map(|n| n.write()); // SAFETY: locked all along and consecutive nodes unsafe { Node::isolate( &pop_node_lock, (BackNodeWriteLock::Head(self_lock), next_node_lock), ); } drop(pop_node_lock); // SAFETY: node has been isolated so no references out unsafe { pop_node.wait_free() } Some(()) } pub fn clone_into_vec(&self) -> Vec where T: Clone, { let mut total = Vec::new(); let mut next_node = self.read().start; while let Some(node) = next_node { let read = node.read(); total.push(read.data.clone()); next_node = read.next; } total } } // Can't quite make this work how I want 😭 /// Attempt to safe wrap around a [`NodeHead`] to allow a sound API with [`Drop`] implementation. /// /// Please see [`create_ll`] and [`del_ll`] pub struct LinkedList<'ll, T> { head: NodeHead<'ll, T>, _pinned: PhantomPinned, } impl<'ll, T> LinkedList<'ll, T> { #[must_use] pub fn new() -> Self { Self::default() } /// # Safety /// /// NEVER EVER EVER extend the lifetime of this beyond the end of scope of the linked list /// itself, it's all good and safe UNTIL it's dropped. /// /// Allows you to associate the lifetime of this to something else to prevent accidentall /// over-extending the lifetime. pub unsafe fn extend_for<'scope>(&self, _: &'scope impl std::any::Any) -> &'ll NodeHead<'ll, T> where 'scope: 'll, { unsafe { transmute(&self.head) } } } impl Default for LinkedList<'_, T> { #[must_use] fn default() -> Self { Self { head: NodeHead::new(), _pinned: PhantomPinned, } } } impl Drop for LinkedList<'_, T> { fn drop(&mut self) { // Extend to 'static so the compiler doesn't cry, we know this covers 'll let myself = unsafe { self.extend_for(&()) }; // And this is `Drop` so there shouldn't be any refs as the end of this function would be // where their lifetime ('ll) ends unsafe { myself.manual_drop() } } } // I'm not so sure this is that much bulletproof but behaves sollidly enough /// Unsafe macro that automatically creates a linked list and an extended reference. /// /// Also creates a `scope = ()` variable at the same level as `$val` to mimic its scope and prevent /// accidental expansion of the unsafe lifetime beyond the current scope. /// /// For example: /// /// ``` /// use concurrent_linked_list::double::{create_ll, del_ll, LinkedList}; /// /// create_ll!(LinkedList::::new(), ll_val, ll); /// ll.prepend("test".to_string()); /// del_ll!(ll_val, ll); /// ``` /// /// But trying to use `ll` after the deletion should fail: /// /// ```compile_fail /// use concurrent_linked_list::double::{create_ll, del_ll, LinkedList}; /// /// create_ll!(LinkedList::::new(), ll_val, ll); /// ll.prepend("test".to_string()); /// del_ll!(ll_val, ll); /// ll.prepend("test2".to_string()); /// ``` /// /// Or trying to expand `ll` beyond the scope it was defined in, even if not deleted: /// /// ```compile_fail /// use concurrent_linked_list::double::{create_ll, del_ll, LinkedList}; /// /// let ll = { /// create_ll!(LinkedList::::new(), ll_val, ll); /// ll.prepend("test".to_string()); /// ll /// } /// ll.prepend("test2".to_string()); /// ``` pub macro create_ll($rhs:expr, $val:ident, $ref:ident) { let $val = $rhs; let scope = (); let $ref = unsafe { $val.extend_for(&scope) }; } /// Macro that attempts to run some higene cleanup on [`create_ll`] to avoid accidental use ot the /// reference further too. Other functions could still extend the lifetime beyond acceptable /// though. pub macro del_ll($val:ident, $ref:ident) { #[allow(unused_variables)] let $ref = (); drop($val); } #[cfg(test)] mod tests;