Path: blob/master/rust/pin-init/examples/linked_list.rs
29278 views
// SPDX-License-Identifier: Apache-2.0 OR MIT12#![allow(clippy::undocumented_unsafe_blocks)]3#![cfg_attr(feature = "alloc", feature(allocator_api))]4#![cfg_attr(not(RUSTC_LINT_REASONS_IS_STABLE), feature(lint_reasons))]56use core::{7cell::Cell,8convert::Infallible,9marker::PhantomPinned,10pin::Pin,11ptr::{self, NonNull},12};1314use pin_init::*;1516#[allow(unused_attributes)]17mod error;18#[allow(unused_imports)]19use error::Error;2021#[pin_data(PinnedDrop)]22#[repr(C)]23#[derive(Debug)]24pub struct ListHead {25next: Link,26prev: Link,27#[pin]28pin: PhantomPinned,29}3031impl ListHead {32#[inline]33pub fn new() -> impl PinInit<Self, Infallible> {34try_pin_init!(&this in Self {35next: unsafe { Link::new_unchecked(this) },36prev: unsafe { Link::new_unchecked(this) },37pin: PhantomPinned,38}? Infallible)39}4041#[inline]42#[allow(dead_code)]43pub fn insert_next(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {44try_pin_init!(&this in Self {45prev: list.next.prev().replace(unsafe { Link::new_unchecked(this)}),46next: list.next.replace(unsafe { Link::new_unchecked(this)}),47pin: PhantomPinned,48}? Infallible)49}5051#[inline]52pub fn insert_prev(list: &ListHead) -> impl PinInit<Self, Infallible> + '_ {53try_pin_init!(&this in Self {54next: list.prev.next().replace(unsafe { Link::new_unchecked(this)}),55prev: list.prev.replace(unsafe { Link::new_unchecked(this)}),56pin: PhantomPinned,57}? Infallible)58}5960#[inline]61pub fn next(&self) -> Option<NonNull<Self>> {62if ptr::eq(self.next.as_ptr(), self) {63None64} else {65Some(unsafe { NonNull::new_unchecked(self.next.as_ptr() as *mut Self) })66}67}6869#[allow(dead_code)]70pub fn size(&self) -> usize {71let mut size = 1;72let mut cur = self.next.clone();73while !ptr::eq(self, cur.cur()) {74cur = cur.next().clone();75size += 1;76}77size78}79}8081#[pinned_drop]82impl PinnedDrop for ListHead {83//#[inline]84fn drop(self: Pin<&mut Self>) {85if !ptr::eq(self.next.as_ptr(), &*self) {86let next = unsafe { &*self.next.as_ptr() };87let prev = unsafe { &*self.prev.as_ptr() };88next.prev.set(&self.prev);89prev.next.set(&self.next);90}91}92}9394#[repr(transparent)]95#[derive(Clone, Debug)]96struct Link(Cell<NonNull<ListHead>>);9798impl Link {99/// # Safety100///101/// The contents of the pointer should form a consistent circular102/// linked list; for example, a "next" link should be pointed back103/// by the target `ListHead`'s "prev" link and a "prev" link should be104/// pointed back by the target `ListHead`'s "next" link.105#[inline]106unsafe fn new_unchecked(ptr: NonNull<ListHead>) -> Self {107Self(Cell::new(ptr))108}109110#[inline]111fn next(&self) -> &Link {112unsafe { &(*self.0.get().as_ptr()).next }113}114115#[inline]116#[allow(dead_code)]117fn prev(&self) -> &Link {118unsafe { &(*self.0.get().as_ptr()).prev }119}120121#[allow(dead_code)]122fn cur(&self) -> &ListHead {123unsafe { &*self.0.get().as_ptr() }124}125126#[inline]127fn replace(&self, other: Link) -> Link {128unsafe { Link::new_unchecked(self.0.replace(other.0.get())) }129}130131#[inline]132fn as_ptr(&self) -> *const ListHead {133self.0.get().as_ptr()134}135136#[inline]137fn set(&self, val: &Link) {138self.0.set(val.0.get());139}140}141142#[allow(dead_code)]143#[cfg(not(any(feature = "std", feature = "alloc")))]144fn main() {}145146#[allow(dead_code)]147#[cfg_attr(test, test)]148#[cfg(any(feature = "std", feature = "alloc"))]149fn main() -> Result<(), Error> {150let a = Box::pin_init(ListHead::new())?;151stack_pin_init!(let b = ListHead::insert_next(&a));152stack_pin_init!(let c = ListHead::insert_next(&a));153stack_pin_init!(let d = ListHead::insert_next(&b));154let e = Box::pin_init(ListHead::insert_next(&b))?;155println!("a ({a:p}): {a:?}");156println!("b ({b:p}): {b:?}");157println!("c ({c:p}): {c:?}");158println!("d ({d:p}): {d:?}");159println!("e ({e:p}): {e:?}");160let mut inspect = &*a;161while let Some(next) = inspect.next() {162println!("({inspect:p}): {inspect:?}");163inspect = unsafe { &*next.as_ptr() };164if core::ptr::eq(inspect, &*a) {165break;166}167}168Ok(())169}170171172