fixed miri issues and wrote docs

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