xref: /linux/rust/pin-init/examples/linked_list.rs (revision ec7714e4947909190ffb3041a03311a975350fe0)
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