pin_arc/
lib.rs

1#![no_std]
2#![deny(unsafe_code)]
3
4//! This crate provides reference counting pointers similar to `Rc` and `Arc`, but without heap allocation.
5//! You are responsible for creating a `Pin{Arc|Rc}Storage`, which you can obtain `Pin{Arc|Rc}` pointers from.
6//! The storage needs to be pinned, for example using [`pin`](core::pin::pin).
7//!
8//! ```rust
9//! # use std::pin::pin;
10//! # use pin_arc::{PinArc, PinArcStorage};
11//! let storage = pin!(PinArcStorage::new(4));
12//! let arc = storage.as_ref().create_handle();
13//! println!("{arc:?}");
14//! ```
15//!
16//! If the storage is dropped before all references to it are released, the program is aborted (even if you have set panics to unwind):
17//! ```should_panic
18//! # use std::pin::pin;
19//! # use pin_arc::{PinArc,PinArcStorage};
20//! fn escaping_handle() -> PinArc<u32> {
21//!     let storage = pin!(PinArcStorage::new(4));
22//!     storage.as_ref().create_handle()
23//! }
24//! escaping_handle();
25//! ```
26
27#[cfg(all(feature = "unsafe_disable_abort", not(debug_assertions)))]
28const _: () = const {
29    panic!("the feature unsafe_disable_abort should only be used for testing this crate. Enabling it makes the api unsound.")
30};
31
32use core::borrow::Borrow;
33use core::cmp::Ordering;
34use core::fmt::{Debug, Formatter};
35use core::hash::{Hash, Hasher};
36use core::ops::Deref;
37use core::pin::Pin;
38use radium::Radium;
39
40#[allow(unsafe_code)]
41mod generic_rc;
42
43use crate::generic_rc::Inner;
44pub use generic_rc::*;
45
46impl<T, C: Radium<Item = usize>> Deref for PinRcGenericStorage<T, C> {
47    type Target = T;
48
49    fn deref(&self) -> &Self::Target {
50        self.inner_unpin().value_unpin()
51    }
52}
53
54impl<T, C: Radium<Item = usize>> PinRcGenericStorage<T, C> {
55    /// Get the number of handles currently referring to `self`.
56    /// Beware of race conditions:
57    /// Concurrent operations may change the count between
58    /// the time you observe it and the time you act on the observation.
59    pub fn ref_count(&self) -> usize {
60        self.inner_unpin().count()
61    }
62
63    /// Get a pinned reference to the contained value.
64    pub fn get_pin(self: Pin<&Self>) -> Pin<&T> {
65        self.inner_pin().value_pin()
66    }
67
68    /// Create a handle referring to `self`.
69    /// Note that this takes `Pin<&Self>`.
70    /// If you have a `Pin<&mut Self>`, call `as_ref`:
71    /// ```rust
72    /// # use std::pin::pin;
73    /// # use pin_arc::{PinArc, PinArcStorage};
74    /// # let storage=pin!(PinArcStorage::new(4));
75    /// let arc = storage.as_ref().create_handle();
76    /// ```
77    pub fn create_handle(self: Pin<&Self>) -> PinRcGeneric<T, C> {
78        self.inner_pin().create_handle()
79    }
80}
81
82impl<T, C: Radium<Item = usize>> PinRcGeneric<T, C> {
83    /// Get the number of handles currently referring to the same storage (including `self`).
84    /// Beware of race conditions:
85    /// Concurrent operations may change the count between
86    /// the time you observe it and the time you act on the observation.
87    pub fn ref_count(&self) -> usize {
88        self.inner_unpin().count()
89    }
90
91    /// Get a pinned reference to the contained value.
92    pub fn get_pin(&self) -> Pin<&T> {
93        self.inner_pin().value_pin()
94    }
95}
96
97impl<T, C: Radium<Item = usize>> Deref for PinRcGeneric<T, C> {
98    type Target = T;
99
100    fn deref(&self) -> &Self::Target {
101        self.inner_pin().value_pin().get_ref()
102    }
103}
104
105impl<T, C: Radium<Item = usize>> Clone for PinRcGeneric<T, C> {
106    fn clone(&self) -> Self {
107        self.inner_pin().create_handle()
108    }
109}
110
111macro_rules! impl_cmp_trait {
112    ($Trait:ident{$($name:ident->$Ret:ty),*} for $For:ident) => {
113        impl<T:$Trait,C:Radium<Item=usize>>  $Trait for $For<T,C>{
114            $(
115                #[inline]
116                fn $name(&self, other: &Self)->$Ret{
117                    <T as $Trait>::$name(&**self,&**other)
118                }
119            )*
120        }
121    };
122}
123
124impl_cmp_trait!(PartialEq{eq->bool} for PinRcGeneric);
125impl_cmp_trait!(Eq{} for PinRcGeneric);
126impl_cmp_trait!(PartialOrd{partial_cmp->Option<Ordering>,lt->bool,le->bool,gt->bool,ge->bool} for PinRcGeneric);
127impl_cmp_trait!(Ord{cmp->Ordering} for PinRcGeneric);
128
129impl_cmp_trait!(PartialEq{eq->bool} for PinRcGenericStorage);
130impl_cmp_trait!(Eq{} for PinRcGenericStorage);
131impl_cmp_trait!(PartialOrd{partial_cmp->Option<Ordering>,lt->bool,le->bool,gt->bool,ge->bool} for PinRcGenericStorage);
132impl_cmp_trait!(Ord{cmp->Ordering} for PinRcGenericStorage);
133
134macro_rules! impl_others {
135    ($For:ident) => {
136        impl<T: Hash, C: Radium<Item = usize>> Hash for $For<T, C> {
137            fn hash<H: Hasher>(&self, state: &mut H) {
138                <T as Hash>::hash(&**self, state)
139            }
140        }
141
142        impl<T, C: Radium<Item = usize>> Borrow<T> for $For<T, C> {
143            fn borrow(&self) -> &T {
144                self
145            }
146        }
147
148        impl<T: Debug, C: Radium<Item = usize>> Debug for $For<T, C> {
149            fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
150                Debug::fmt(self.inner_unpin(), f)
151            }
152        }
153    };
154}
155
156impl_others!(PinRcGeneric);
157impl_others!(PinRcGenericStorage);
158
159impl<T: Debug, C: Radium<Item = usize>> Debug for Inner<T, C> {
160    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
161        let mut s = f.debug_struct("PinRcGeneric");
162        s.field("ref_count", &self.count());
163        s.field("value", self.value_unpin());
164        s.finish()
165    }
166}