// SPDX-License-Identifier: Apache-2.0 OR MIT #![allow(clippy::undocumented_unsafe_blocks)]#![cfg_attr(feature = "alloc", feature(allocator_api))] use core::{ cell::Cell, marker::PhantomPinned, pin::Pin, ptr::{self, NonNull},}; use pin_init::*; #[allow(unused_attributes)]mod error;#[allow(unused_imports)]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<Self> { pin_init!(&this in Self { next: unsafe { Link::new_unchecked(this) }, prev: unsafe { Link::new_unchecked(this) }, pin: PhantomPinned, }) } #[inline] #[allow(dead_code)] pub fn insert_next(list: &ListHead) -> impl PinInit<Self> + '_ { 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, }) } #[inline] pub fn insert_prev(list: &ListHead) -> impl PinInit<Self> + '_ { 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, }) } #[inline] pub fn next(&self) -> Option<NonNull<Self>> { 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<NonNull<ListHead>>); impl Link { /// # Safety /// /// The contents of the pointer should form a consistent circular /// linked list; for example, a "next" link should be pointed back /// by the target `ListHead`'s "prev" link and a "prev" link should be /// pointed back by the target `ListHead`'s "next" link. #[inline] unsafe fn new_unchecked(ptr: NonNull<ListHead>) -> Self { Self(Cell::new(ptr)) } #[inline] fn next(&self) -> &Link { unsafe { &(*self.0.get().as_ptr()).next } } #[inline] #[allow(dead_code)] 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(not(any(feature = "std", feature = "alloc")))]fn main() {} #[allow(dead_code)]#[cfg_attr(test, test)]#[cfg(any(feature = "std", feature = "alloc"))]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(())}
// SPDX-License-Identifier: Apache-2.0 OR MIT
#![allow(clippy::undocumented_unsafe_blocks)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
use core::{
cell::Cell,
marker::PhantomPinned,
pin::Pin,
ptr::{self, NonNull},
};
use pin_init::*;
#[allow(unused_attributes)]
mod error;
#[allow(unused_imports)]
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<Self> {
pin_init!(&this in Self {
next: unsafe { Link::new_unchecked(this) },
prev: unsafe { Link::new_unchecked(this) },
pin: PhantomPinned,
})
}
#[inline]
#[allow(dead_code)]
pub fn insert_next(list: &ListHead) -> impl PinInit<Self> + '_ {
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,
})
}
#[inline]
pub fn insert_prev(list: &ListHead) -> impl PinInit<Self> + '_ {
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,
})
}
#[inline]
pub fn next(&self) -> Option<NonNull<Self>> {
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<NonNull<ListHead>>);
impl Link {
/// # Safety
///
/// The contents of the pointer should form a consistent circular
/// linked list; for example, a "next" link should be pointed back
/// by the target `ListHead`'s "prev" link and a "prev" link should be
/// pointed back by the target `ListHead`'s "next" link.
#[inline]
unsafe fn new_unchecked(ptr: NonNull<ListHead>) -> Self {
Self(Cell::new(ptr))
}
#[inline]
fn next(&self) -> &Link {
unsafe { &(*self.0.get().as_ptr()).next }
}
#[inline]
#[allow(dead_code)]
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(not(any(feature = "std", feature = "alloc")))]
fn main() {}
#[allow(dead_code)]
#[cfg_attr(test, test)]
#[cfg(any(feature = "std", feature = "alloc"))]
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(())
}