184837cf6SBenno Lossin // SPDX-License-Identifier: Apache-2.0 OR MIT
284837cf6SBenno Lossin
384837cf6SBenno Lossin #![allow(clippy::undocumented_unsafe_blocks)]
484837cf6SBenno Lossin #![cfg_attr(feature = "alloc", feature(allocator_api))]
5*5c4167b4SBenno Lossin #![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]
684837cf6SBenno Lossin
784837cf6SBenno Lossin use core::{
884837cf6SBenno Lossin cell::Cell,
984837cf6SBenno Lossin convert::Infallible,
1084837cf6SBenno Lossin marker::PhantomPinned,
1184837cf6SBenno Lossin pin::Pin,
1284837cf6SBenno Lossin ptr::{self, NonNull},
1384837cf6SBenno Lossin };
1484837cf6SBenno Lossin
1584837cf6SBenno Lossin use pin_init::*;
1684837cf6SBenno Lossin
1784837cf6SBenno Lossin #[expect(unused_attributes)]
1884837cf6SBenno Lossin mod error;
1984837cf6SBenno Lossin use error::Error;
2084837cf6SBenno Lossin
2184837cf6SBenno Lossin #[pin_data(PinnedDrop)]
2284837cf6SBenno Lossin #[repr(C)]
2384837cf6SBenno Lossin #[derive(Debug)]
2484837cf6SBenno Lossin pub struct ListHead {
2584837cf6SBenno Lossin next: Link,
2684837cf6SBenno Lossin prev: Link,
2784837cf6SBenno Lossin #[pin]
2884837cf6SBenno Lossin pin: PhantomPinned,
2984837cf6SBenno Lossin }
3084837cf6SBenno Lossin
3184837cf6SBenno Lossin impl ListHead {
3284837cf6SBenno Lossin #[inline]
new() -> impl PinInit<Self, Infallible>3384837cf6SBenno Lossin pub fn new() -> impl PinInit<Self, Infallible> {
3484837cf6SBenno Lossin try_pin_init!(&this in Self {
3584837cf6SBenno Lossin next: unsafe { Link::new_unchecked(this) },
3684837cf6SBenno Lossin prev: unsafe { Link::new_unchecked(this) },
3784837cf6SBenno Lossin pin: PhantomPinned,
3884837cf6SBenno Lossin }? Infallible)
3984837cf6SBenno Lossin }
4084837cf6SBenno Lossin
4184837cf6SBenno Lossin #[inline]
insert_next(list: &ListHead) -> impl PinInit<Self, Infallible> + '_4284837cf6SBenno Lossin pub fn insert_next(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {
4384837cf6SBenno Lossin try_pin_init!(&this in Self {
4484837cf6SBenno Lossin prev: list.next.prev().replace(unsafe { Link::new_unchecked(this)}),
4584837cf6SBenno Lossin next: list.next.replace(unsafe { Link::new_unchecked(this)}),
4684837cf6SBenno Lossin pin: PhantomPinned,
4784837cf6SBenno Lossin }? Infallible)
4884837cf6SBenno Lossin }
4984837cf6SBenno Lossin
5084837cf6SBenno Lossin #[inline]
insert_prev(list: &ListHead) -> impl PinInit<Self, Infallible> + '_5184837cf6SBenno Lossin pub fn insert_prev(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {
5284837cf6SBenno Lossin try_pin_init!(&this in Self {
5384837cf6SBenno Lossin next: list.prev.next().replace(unsafe { Link::new_unchecked(this)}),
5484837cf6SBenno Lossin prev: list.prev.replace(unsafe { Link::new_unchecked(this)}),
5584837cf6SBenno Lossin pin: PhantomPinned,
5684837cf6SBenno Lossin }? Infallible)
5784837cf6SBenno Lossin }
5884837cf6SBenno Lossin
5984837cf6SBenno Lossin #[inline]
next(&self) -> Option<NonNull<Self>>6084837cf6SBenno Lossin pub fn next(&self) -> Option<NonNull<Self>> {
6184837cf6SBenno Lossin if ptr::eq(self.next.as_ptr(), self) {
6284837cf6SBenno Lossin None
6384837cf6SBenno Lossin } else {
6484837cf6SBenno Lossin Some(unsafe { NonNull::new_unchecked(self.next.as_ptr() as *mut Self) })
6584837cf6SBenno Lossin }
6684837cf6SBenno Lossin }
6784837cf6SBenno Lossin
6884837cf6SBenno Lossin #[allow(dead_code)]
size(&self) -> usize6984837cf6SBenno Lossin pub fn size(&self) -> usize {
7084837cf6SBenno Lossin let mut size = 1;
7184837cf6SBenno Lossin let mut cur = self.next.clone();
7284837cf6SBenno Lossin while !ptr::eq(self, cur.cur()) {
7384837cf6SBenno Lossin cur = cur.next().clone();
7484837cf6SBenno Lossin size += 1;
7584837cf6SBenno Lossin }
7684837cf6SBenno Lossin size
7784837cf6SBenno Lossin }
7884837cf6SBenno Lossin }
7984837cf6SBenno Lossin
8084837cf6SBenno Lossin #[pinned_drop]
8184837cf6SBenno Lossin impl PinnedDrop for ListHead {
8284837cf6SBenno Lossin //#[inline]
drop(self: Pin<&mut Self>)8384837cf6SBenno Lossin fn drop(self: Pin<&mut Self>) {
8484837cf6SBenno Lossin if !ptr::eq(self.next.as_ptr(), &*self) {
8584837cf6SBenno Lossin let next = unsafe { &*self.next.as_ptr() };
8684837cf6SBenno Lossin let prev = unsafe { &*self.prev.as_ptr() };
8784837cf6SBenno Lossin next.prev.set(&self.prev);
8884837cf6SBenno Lossin prev.next.set(&self.next);
8984837cf6SBenno Lossin }
9084837cf6SBenno Lossin }
9184837cf6SBenno Lossin }
9284837cf6SBenno Lossin
9384837cf6SBenno Lossin #[repr(transparent)]
9484837cf6SBenno Lossin #[derive(Clone, Debug)]
9584837cf6SBenno Lossin struct Link(Cell<NonNull<ListHead>>);
9684837cf6SBenno Lossin
9784837cf6SBenno Lossin impl Link {
9884837cf6SBenno Lossin /// # Safety
9984837cf6SBenno Lossin ///
10084837cf6SBenno Lossin /// The contents of the pointer should form a consistent circular
10184837cf6SBenno Lossin /// linked list; for example, a "next" link should be pointed back
10284837cf6SBenno Lossin /// by the target `ListHead`'s "prev" link and a "prev" link should be
10384837cf6SBenno Lossin /// pointed back by the target `ListHead`'s "next" link.
10484837cf6SBenno Lossin #[inline]
new_unchecked(ptr: NonNull<ListHead>) -> Self10584837cf6SBenno Lossin unsafe fn new_unchecked(ptr: NonNull<ListHead>) -> Self {
10684837cf6SBenno Lossin Self(Cell::new(ptr))
10784837cf6SBenno Lossin }
10884837cf6SBenno Lossin
10984837cf6SBenno Lossin #[inline]
next(&self) -> &Link11084837cf6SBenno Lossin fn next(&self) -> &Link {
11184837cf6SBenno Lossin unsafe { &(*self.0.get().as_ptr()).next }
11284837cf6SBenno Lossin }
11384837cf6SBenno Lossin
11484837cf6SBenno Lossin #[inline]
prev(&self) -> &Link11584837cf6SBenno Lossin fn prev(&self) -> &Link {
11684837cf6SBenno Lossin unsafe { &(*self.0.get().as_ptr()).prev }
11784837cf6SBenno Lossin }
11884837cf6SBenno Lossin
11984837cf6SBenno Lossin #[allow(dead_code)]
cur(&self) -> &ListHead12084837cf6SBenno Lossin fn cur(&self) -> &ListHead {
12184837cf6SBenno Lossin unsafe { &*self.0.get().as_ptr() }
12284837cf6SBenno Lossin }
12384837cf6SBenno Lossin
12484837cf6SBenno Lossin #[inline]
replace(&self, other: Link) -> Link12584837cf6SBenno Lossin fn replace(&self, other: Link) -> Link {
12684837cf6SBenno Lossin unsafe { Link::new_unchecked(self.0.replace(other.0.get())) }
12784837cf6SBenno Lossin }
12884837cf6SBenno Lossin
12984837cf6SBenno Lossin #[inline]
as_ptr(&self) -> *const ListHead13084837cf6SBenno Lossin fn as_ptr(&self) -> *const ListHead {
13184837cf6SBenno Lossin self.0.get().as_ptr()
13284837cf6SBenno Lossin }
13384837cf6SBenno Lossin
13484837cf6SBenno Lossin #[inline]
set(&self, val: &Link)13584837cf6SBenno Lossin fn set(&self, val: &Link) {
13684837cf6SBenno Lossin self.0.set(val.0.get());
13784837cf6SBenno Lossin }
13884837cf6SBenno Lossin }
13984837cf6SBenno Lossin
14084837cf6SBenno Lossin #[allow(dead_code)]
14184837cf6SBenno Lossin #[cfg_attr(test, test)]
main() -> Result<(), Error>14284837cf6SBenno Lossin fn main() -> Result<(), Error> {
14384837cf6SBenno Lossin let a = Box::pin_init(ListHead::new())?;
14484837cf6SBenno Lossin stack_pin_init!(let b = ListHead::insert_next(&a));
14584837cf6SBenno Lossin stack_pin_init!(let c = ListHead::insert_next(&a));
14684837cf6SBenno Lossin stack_pin_init!(let d = ListHead::insert_next(&b));
14784837cf6SBenno Lossin let e = Box::pin_init(ListHead::insert_next(&b))?;
14884837cf6SBenno Lossin println!("a ({a:p}): {a:?}");
14984837cf6SBenno Lossin println!("b ({b:p}): {b:?}");
15084837cf6SBenno Lossin println!("c ({c:p}): {c:?}");
15184837cf6SBenno Lossin println!("d ({d:p}): {d:?}");
15284837cf6SBenno Lossin println!("e ({e:p}): {e:?}");
15384837cf6SBenno Lossin let mut inspect = &*a;
15484837cf6SBenno Lossin while let Some(next) = inspect.next() {
15584837cf6SBenno Lossin println!("({inspect:p}): {inspect:?}");
15684837cf6SBenno Lossin inspect = unsafe { &*next.as_ptr() };
15784837cf6SBenno Lossin if core::ptr::eq(inspect, &*a) {
15884837cf6SBenno Lossin break;
15984837cf6SBenno Lossin }
16084837cf6SBenno Lossin }
16184837cf6SBenno Lossin Ok(())
16284837cf6SBenno Lossin }
163