// SPDX-License-Identifier: Apache-2.0 OR MIT
#! [allow(clippy::undocumented_unsafe_blocks)]
#! [cfg_attr(feature = "alloc" , feature(allocator_api))]
#! [cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
use core::{
cell::Cell,
convert::Infallible,
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 , Infallible> {
try_pin_init!(&this in Self {
next: unsafe { Link::new_unchecked(this) },
prev: unsafe { Link::new_unchecked(this) },
pin: PhantomPinned,
}? Infallible)
}
#[ inline]
#[ allow(dead_code)]
pub fn insert_next(list: &ListHead) -> impl PinInit<Self , Infallible> + '_ {
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<Self , Infallible> + '_ {
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<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(())
}
Messung V0.5 in Prozent C=96 H=73 G=85
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-19)
¤
*© Formatika GbR, Deutschland