#![cfg_attr(feature = "alloc", feature(allocator_api))] use core::{ cell::Cell, convert::Infallible, marker::PhantomPinned, pin::Pin, ptr::{self, NonNull}, }; use pinned_init::*; mod error; pub use error::Error; #[pin_data(PinnedDrop)] #[repr(C)] #[derive(Debug)] pub struct ListHead { next: Link, prev: Link, #[pin] pin: PhantomPinned, } impl ListHead { #[inline] pub fn new() -> impl PinInit { try_pin_init!(&this in Self { next: unsafe { Link::new_unchecked(this) }, prev: unsafe { Link::new_unchecked(this) }, pin: PhantomPinned, }? Infallible) } #[inline] pub fn insert_next(list: &ListHead) -> impl PinInit + '_ { try_pin_init!(&this in Self { prev: list.next.prev().replace(unsafe { Link::new_unchecked(this)}), next: list.next.replace(unsafe { Link::new_unchecked(this)}), pin: PhantomPinned, }? Infallible) } #[inline] pub fn insert_prev(list: &ListHead) -> impl PinInit + '_ { try_pin_init!(&this in Self { next: list.prev.next().replace(unsafe { Link::new_unchecked(this)}), prev: list.prev.replace(unsafe { Link::new_unchecked(this)}), pin: PhantomPinned, }? Infallible) } #[inline] pub fn next(&self) -> Option> { if ptr::eq(self.next.as_ptr(), self) { None } else { Some(unsafe { NonNull::new_unchecked(self.next.as_ptr() as *mut Self) }) } } #[allow(dead_code)] pub fn size(&self) -> usize { let mut size = 1; let mut cur = self.next.clone(); while !ptr::eq(self, cur.cur()) { cur = cur.next().clone(); size += 1; } size } } #[pinned_drop] impl PinnedDrop for ListHead { //#[inline] fn drop(self: Pin<&mut Self>) { if !ptr::eq(self.next.as_ptr(), &*self) { let next = unsafe { &*self.next.as_ptr() }; let prev = unsafe { &*self.prev.as_ptr() }; next.prev.set(&self.prev); prev.next.set(&self.next); } } } #[repr(transparent)] #[derive(Clone, Debug)] struct Link(Cell>); impl Link { #[inline] unsafe fn new_unchecked(ptr: NonNull) -> Self { Self(Cell::new(ptr)) } #[inline] fn next(&self) -> &Link { unsafe { &(*self.0.get().as_ptr()).next } } #[inline] fn prev(&self) -> &Link { unsafe { &(*self.0.get().as_ptr()).prev } } #[allow(dead_code)] fn cur(&self) -> &ListHead { unsafe { &*self.0.get().as_ptr() } } #[inline] fn replace(&self, other: Link) -> Link { unsafe { Link::new_unchecked(self.0.replace(other.0.get())) } } #[inline] fn as_ptr(&self) -> *const ListHead { self.0.get().as_ptr() } #[inline] fn set(&self, val: &Link) { self.0.set(val.0.get()); } } #[allow(dead_code)] #[cfg_attr(test, test)] fn main() -> Result<(), Error> { let a = Box::pin_init(ListHead::new())?; stack_pin_init!(let b = ListHead::insert_next(&a)); stack_pin_init!(let c = ListHead::insert_next(&a)); stack_pin_init!(let d = ListHead::insert_next(&b)); let e = Box::pin_init(ListHead::insert_next(&b))?; println!("a ({a:p}): {a:?}"); println!("b ({b:p}): {b:?}"); println!("c ({c:p}): {c:?}"); println!("d ({d:p}): {d:?}"); println!("e ({e:p}): {e:?}"); let mut inspect = &*a; while let Some(next) = inspect.next() { println!("({inspect:p}): {inspect:?}"); inspect = unsafe { &*next.as_ptr() }; if core::ptr::eq(inspect, &*a) { break; } } Ok(()) }