lifetime_guard/lib.rs
1//! # Lifetime Guard
2//!
3//! `lifetime-guard` provides `ValueGuard` and `RefGuard` structs to allow for
4//! weak references to interior mutable values, similar to a singular pair of
5//! `Rc` and `Weak`, but without heap allocation.
6//!
7//! ## Example Usage
8//!
9//! ```rust
10//! use std::pin;
11//! use lifetime_guard::{ ValueGuard, RefGuard };
12//!
13//! let weak = pin::pin!(RefGuard::new());
14//! {
15//! let strong = pin::pin!(ValueGuard::new(0));
16//! strong.as_ref().registration().register(weak.as_ref());
17//!
18//! assert_eq!(strong.get(), 0);
19//! assert_eq!(weak.get(), Some(0));
20//!
21//! strong.as_ref().set(1);
22//! assert_eq!(strong.get(), 1);
23//! assert_eq!(weak.get(), Some(1));
24//! }
25//! assert_eq!(weak.get(), None);
26//! ```
27//!
28//! # Safety
29//!
30//! You *may not* leak any instance of either `ValueGuard` or `RefGuard` to the
31//! stack using `mem::forget()` or any other mechanism that causes thier
32//! contents to be overwritten without `Drop::drop()` running.
33//! Doing so creates unsoundness that likely will lead to dereferencing a null
34//! pointer.
35//!
36//! Doing so creates unsoundness that likely will lead to dereferencing a null
37//! pointer. See the
38//! [Forget marker trait](https://github.com/rust-lang/rfcs/pull/3782) rfc for
39//! progress on making interfaces that rely on not being leaked sound.
40//!
41//! Note that it is sound to leak `ValueGuard` and `RefGuard` to the heap using
42//! methods including `Box::leak()` because heap allocated data will never be
43//! overwritten if it is never freed.
44
45use std::{cell::Cell, marker::PhantomPinned, pin::Pin, ptr::NonNull};
46
47/// Strong guard for granting read access to a single interior mutable value to
48/// `RefGuard`.
49///
50/// A `ValueGuard`:`RefGuard` relationship is exclusive, and behaves similarly
51/// to a single `Rc` and `Weak` pair, but notably does not require heap
52/// allocation. `ValueGuard::registration` creates a `GuardRegistration`, which
53/// provides a movable wrapper for safety creating the circular references
54/// between two pinned self referential structs.
55///
56/// # Safety
57///
58/// This struct *must* not be leaked to the stack using `mem::forget` or any
59/// other mechanism that causes the contents of `Self` to be overwritten
60/// without `Drop::drop()` running.
61/// Doing so creates unsoundness that likely will lead to dereferencing a null
62/// pointer.
63///
64/// Note that it is sound to leak `Self` to the heap using methods including
65/// `Box::leak()` because heap allocated data will never be overwritten if it
66/// is never freed.
67pub struct ValueGuard<T> {
68 /// Contains the value being immutably accessed by `RefGuard` and
69 /// mutably accessed by `Self`
70 ///
71 /// This needs to be a cell so that the original immutable alias
72 /// to `Self` (given to `RefGuard`) can continue to be referenced after
73 /// invalidated by the creation of a mutable alias for `Self::set`.
74 data: Cell<T>,
75 /// A pointer to a `RefGuard` with read access to `data` to invalidate that
76 /// `RefGuard` when `Self` is dropped.
77 ref_guard: Cell<Option<NonNull<RefGuard<T>>>>,
78 _marker: PhantomPinned,
79}
80
81impl<T> ValueGuard<T> {
82 /// Creates a new `ValueGuard` containing `data`.
83 #[inline]
84 pub fn new(data: T) -> Self {
85 Self {
86 data: Cell::new(data),
87 ref_guard: Cell::new(None),
88 _marker: PhantomPinned,
89 }
90 }
91
92 /// Returns a `GuardRegistration`, which can be used to safety link `Self`
93 /// to a `RefGuard`.
94 #[inline]
95 pub fn registration<'a>(self: Pin<&'a Self>) -> GuardRegistration<'a, T> {
96 GuardRegistration { value_guard: self }
97 }
98
99 /// Sets the internal value stored by `Self`.
100 #[inline]
101 pub fn set(&self, value: T) {
102 self.data.set(value);
103 }
104}
105
106/// Helper function to invalidate a `ValueGuard`'s `RefGuard` reference
107#[inline]
108fn invalidate_value_guard<T>(guard: NonNull<ValueGuard<T>>) {
109 unsafe { (*guard.as_ptr()).ref_guard.set(None) };
110}
111
112impl<T: Copy> ValueGuard<T> {
113 /// Gets a copy of the value stored inside this `ValueGuard`.
114 #[inline]
115 pub fn get(&self) -> T {
116 self.data.get()
117 }
118}
119
120impl<T> Drop for ValueGuard<T> {
121 #[inline]
122 fn drop(&mut self) {
123 if let Some(guard) = self.ref_guard.get() {
124 invalidate_ref_guard(guard);
125 }
126 }
127}
128
129/// Weak guard for acquiring read only access to a `ValueGuard`'s value.
130///
131/// # Safety
132///
133/// This struct *must* not be leaked to the stack using `mem::forget` or any
134/// other mechanism that causes the contents of `Self` to be overwritten
135/// without `Drop::drop()` running.
136/// Doing so creates unsoundness that likely will lead to dereferencing a null
137/// pointer.
138///
139/// Note that it is sound to leak `Self` to the heap using methods including
140/// `Box::leak()` because heap allocated data will never be overwritten if it
141/// is never freed.
142pub struct RefGuard<T> {
143 value_guard: Cell<Option<NonNull<ValueGuard<T>>>>,
144 _marker: PhantomPinned,
145}
146
147impl<T> RefGuard<T> {
148 /// Creates a new `RefGuard` with no reference to a `ValueGuard`.
149 #[inline]
150 pub fn new() -> Self {
151 Self {
152 value_guard: Cell::new(None),
153 _marker: PhantomPinned,
154 }
155 }
156}
157
158/// Helper function to invalidate a `RefGuard`'s `ValueGuard` reference
159#[inline]
160fn invalidate_ref_guard<T>(guard: NonNull<RefGuard<T>>) {
161 unsafe { (*guard.as_ptr()).value_guard.set(None) };
162}
163
164impl<T: Copy> RefGuard<T> {
165 /// Gets a copy of the value stored inside the `ValueGuard` this `RefGuard`
166 /// references.
167 #[inline]
168 pub fn get(&self) -> Option<T> {
169 self.value_guard
170 .get()
171 .map(|guard| unsafe { (*guard.as_ptr()).get() })
172 }
173}
174
175impl<T> Drop for RefGuard<T> {
176 #[inline]
177 fn drop(&mut self) {
178 if let Some(guard) = self.value_guard.get() {
179 invalidate_value_guard(guard);
180 }
181 }
182}
183
184impl<T> Default for RefGuard<T> {
185 #[inline]
186 fn default() -> Self {
187 Self::new()
188 }
189}
190
191/// Safe api for creating self reference between a pinned `ValueGuard` and
192/// `RefGuard` pair.
193///
194/// This can be acquired with
195/// [`ValueGuard::registration()`](ValueGuard::registration).
196pub struct GuardRegistration<'a, T> {
197 value_guard: Pin<&'a ValueGuard<T>>,
198}
199
200impl<'a, T> GuardRegistration<'a, T> {
201 /// Binds a provided `slot` to the `self.value_guard`.
202 ///
203 /// This means they will reference each other, and will invalidate their
204 /// references to each other when dropped.
205 ///
206 /// This method also invalidates the existing references held by the
207 /// now-replaced referencees of `slot` and `self.value_guard` to avoid
208 /// dangling pointers.
209 pub fn register(self, slot: Pin<&'a RefGuard<T>>) {
210 // replace slot's value guard with reference to self.value_guard
211 // and invalidate slot's old value guard if it exists
212 if let Some(old_guard) = slot
213 .value_guard
214 .replace(Some(self.value_guard.get_ref().into()))
215 {
216 invalidate_value_guard(old_guard);
217 }
218
219 // replace self.value_guard's ref guard with reference to slot
220 // and invalidate self.value_guard's old ref guard if it exists
221 if let Some(old_guard) = self
222 .value_guard
223 .ref_guard
224 .replace(Some(slot.get_ref().into()))
225 {
226 invalidate_ref_guard(old_guard);
227 }
228 }
229}
230
231#[cfg(test)]
232mod test {
233 use std::{mem, pin};
234
235 use super::*;
236
237 #[test]
238 fn basic() {
239 let weak = pin::pin!(RefGuard::new());
240 {
241 let strong = pin::pin!(ValueGuard::new(2));
242 strong.as_ref().registration().register(weak.as_ref());
243
244 assert_eq!(strong.get(), 2);
245 assert_eq!(weak.get(), Some(2));
246
247 strong.as_ref().set(3);
248 assert_eq!(strong.get(), 3);
249 assert_eq!(weak.get(), Some(3));
250 }
251
252 assert_eq!(weak.get(), None);
253 }
254
255 #[test]
256 fn multiple_registrations() {
257 let weak1 = pin::pin!(RefGuard::new());
258 let weak2 = pin::pin!(RefGuard::new());
259 {
260 let strong = pin::pin!(ValueGuard::new(2));
261 strong.as_ref().registration().register(weak1.as_ref());
262
263 assert_eq!(strong.get(), 2);
264 assert_eq!(weak1.get(), Some(2));
265
266 strong.as_ref().set(3);
267 assert_eq!(strong.get(), 3);
268 assert_eq!(weak1.get(), Some(3));
269
270 // register next ptr, should invalidate previous weak ref (weak1)
271 strong.as_ref().registration().register(weak2.as_ref());
272 assert_eq!(weak1.get(), None);
273 assert_eq!(weak1.value_guard.get(), None);
274
275 assert_eq!(strong.get(), 3);
276 assert_eq!(weak2.get(), Some(3));
277
278 strong.as_ref().set(4);
279 assert_eq!(strong.get(), 4);
280 assert_eq!(weak2.get(), Some(4));
281 }
282
283 assert_eq!(weak1.get(), None);
284 assert_eq!(weak2.get(), None);
285 }
286
287 #[test]
288 #[cfg_attr(miri, ignore)]
289 fn safe_leak() {
290 let strong = Box::pin(ValueGuard::new(10));
291 let weak = pin::pin!(RefGuard::new());
292 strong.as_ref().registration().register(weak.as_ref());
293
294 // strong is now a ValueGuard on the heap that will never be freed
295 // this is sound because it will never be overwritten
296 mem::forget(strong);
297
298 assert_eq!(weak.get(), Some(10));
299 }
300}