1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
use core::ptr::NonNull; use crate::Reference; /// A smart pointer which holds a "deferred reference" to an instance of type `T: ?Sized`. /// It has all the properties of a normal reference (`&T` or `&mut T`), /// except that it does not hold an actual reference. This makes it possible pass /// around multiple deferred references in unsafe code, without triggering /// undefined behavior due to existence of aliased mutable references. `Deferred` /// aims to make it easier to reason about the validity and lifetime of pointers /// during the act of dereferencing. /// /// # Invariant /// `Deferred` upholds the same guarantees as its referenceable counter-parts `&T` /// and `&mut T` (except that it doesn't occupy an actual reference!), it is possible /// to always dereference it: /// * The address that `Deferred` points to is guaranteed to be properly aligned. /// * `Deferred` is guaranteed to be non-dangling. /// * `Deferred` is guaranteed to be non-null. /// * `Deferred` is guaranteed to dereference to the same (stack-allocated) object. /// * The memory that `Deferred` points to is guaranteed to be properly initialized. /// * `Deferred` is guaranteed to be valid for the duration of its lifetime. /// /// For mutable pointers, `Deferred<&mut T>` guarantees that no mutable reference(s) existed /// to (any part of) the `T` instance at the time the `Deferred` was constructed. After /// a mutable `Deferred<&mut T>` is created, mutable references may be constructed from it /// (safely or unsafely), but the Rust aliasing rules must always be respected, meaning /// no two live mutable references may point to overlapping regions in memory, ever. /// /// # Safety /// Even though it is possible to work with `Deferred` from purely safe Rust, it also offers /// additional functionality in `unsafe` code and then the programmer must take special care when /// dereferencing the `Deferred` or its pointers in unsafe code regarding the usual Rust rules: /// * Don't create a mutable reference `&mut T` to regions of the memory which already /// hold an immutable reference `&T` or a mutable reference `&mut T`. /// The usual Rust aliasing rules still apply, even in unsafe code! /// * Don't create any reference, `&T` or `&mut T`, to regions of the memory which /// could be modified from other threads or processes. /// * Don't create any mutable reference `&mut T` to regions of the memory which /// could be aliased through a `&T` or `&mut T` from other threads or processes. /// * Creating immutable aliases `&T` to regions of the memory is fine as long as there /// are only readers for the same part of the slice, even if it is read from other /// threads or processes. #[repr(transparent)] // this is so that it can be casted to and from other pointers pub struct Deferred<T> where T: Reference, { /// The raw pointer. This pointer may never dangle and must always be valid. ptr: NonNull<T::Target>, } /// # Constructors for deferred _immutable_ references /// There exist several ways to construct a deferred immutable reference `Deferred<&T>`, listed here in /// order of safety (lower in the list means it's more unsafe). /// 1. Through the [Deferred::new] method. /// 2. Through the [From]/[Into] traits implemented for `Deferred<&T>`. /// 3. Through the [Defer::defer](crate::Defer::defer) method on types that implement the [Defer](crate::Defer) trait. /// 4. Through the _unsafe_ [Deferred::from_raw] method. /// 5. Through the _extremely unsafe_ [`defer`](macro@defer) macro (not recommended). impl<'a, T: ?Sized> Deferred<&'a T> { /// Construct a new deferred immutable reference from an existing immutable reference. /// ``` /// use deferred_reference::Deferred; /// let x = [1, 2, 3]; /// let deferred = Deferred::new(&x); /// assert_eq!(2, deferred[1]); /// ``` pub fn new(reference: &'a T) -> Self { // SAFETY: an actual reference upholds the same guarantees as [Deferred], to this is safe. unsafe { Self::from_raw(reference) } } /// Construct a new deferred immutable reference to an instance of `T: ?Sized` from a raw pointer. /// This method is unsafe. For a safe alternative, use `Deferred::from(&T)` instead. If you don't /// have access to a reference or don't want to create one, then this method (`Deferred::from_raw`) /// is the method that you could use instead. Alternatively, another safe method is to call the /// [Defer::defer](crate::Defer::defer) method on types that implement the [Defer](crate::Defer) trait. /// /// # Safety /// The caller must uphold the invariant of [Deferred], which implies guaranteeing /// largely the same safety guarantees as for regular immutable references. /// Most importantly this means that the pointer must be derefenceable and may not contain /// any part of memory which is left uninitialized. Referencing uninitialized memory of /// any type is always instant undefined behavior (see the nomicon at /// <https://doc.rust-lang.org/nomicon/uninitialized.html> for more details on this fact). /// The caller must also ensure that the pointer remains valid for as long as the returned /// `Deferred` exists. If the pointers refers to a shared memory (mapped) region which may /// be modified somehow, then it is also the caller's reponsibility never to call safe /// methods such as [`<Deferred as Deref>::deref`](core::ops::Deref::deref). This would /// alias the entire memory region and is only safe if there are no writers at the same time. /// /// # Caveat /// The lifetime for the returned [Deferred] is inferred from its usage. To prevent accidental misuse, /// it's suggested to tie the lifetime to whichever source lifetime is safe in the context, such as /// by providing a helper function taking the lifetime of a host value, or by explicit annotation. /// ``` /// use deferred_reference::Deferred; /// pub trait MemoryMappedBuffer { /// fn as_ptr(&self) -> *const u8; /// fn len(&self) -> usize; /// } /// fn defer<'a, T>(buffer: &'a T) -> Deferred<&'a [u8]> /// where /// T: MemoryMappedBuffer /// { /// let slice_ptr = core::ptr::slice_from_raw_parts(buffer.as_ptr(), buffer.len()); /// unsafe { Deferred::from_raw(slice_ptr) } /// } /// ``` /// /// # Example /// ``` /// use deferred_reference::Deferred; /// let buffer = [0u8; 1024]; /// // SAFETY: `buffer` is not moved or mutably aliased after this. /// let deferred = unsafe { Deferred::from_raw(core::ptr::addr_of!(buffer)) }; /// ``` pub unsafe fn from_raw(ptr: *const T) -> Self { // note: this method must live in the impl for `&'a T` // otherwise Rust can't infer the type properly. Self { // note: the pointer is casted from `*const T` to `*mut T`, but this is safe because // this is not undefined behavior. dereferencing the `*mut T` would be UB, // but there is no way to do this if it was constructed from a *const T, // so this is still sound. ptr: NonNull::new_unchecked(ptr as *mut T), } } } /// # Constructors for deferred _mutable_ references /// There exist several ways to construct a deferred mutable reference `Deferred<&mut T>`, listed here in /// order of safety (lower in the list means it's more unsafe). /// 1. Through the [Deferred::new_mut] method. /// 2. Through the [From]/[Into] traits implemented for `Deferred<&mut T>`. /// 3. Through the _unsafe_ [DeferMut::defer_mut](crate::DeferMut::defer_mut) method on types that implement the [DeferMut](crate::DeferMut) trait. /// 4. Through the _unsafe_ [Deferred::from_raw_mut] method. /// 5. Through the _extremely unsafe_ [`defer_mut`](macro@defer_mut) macro (not recommended). impl<'a, T: ?Sized> Deferred<&'a mut T> { /// Construct a new deferred mutable reference from an existing mutable reference. /// ``` /// use deferred_reference::Deferred; /// let mut x = [1, 2, 3]; /// let mut deferred = Deferred::new_mut(&mut x); /// assert_eq!(&mut 2, &mut deferred[1]); /// ``` pub fn new_mut(reference: &'a mut T) -> Self { // SAFETY: an actual reference upholds the same guarantees as [Deferred], to this is safe. unsafe { Self::from_raw_mut(reference) } } /// Construct a new deferred mutable reference to an instance of `T`. /// /// # Safety /// The caller must uphold the invariant of [Deferred]. Most importantly this means that the pointer must be /// derefenceable and may not contain any part of memory which is left uninitialized. Referencing /// uninitialized memory of any type is always instant undefined behavior (see the nomicon at /// <https://doc.rust-lang.org/nomicon/uninitialized.html> for more details on this fact). /// On top of that, the caller must ensure that the pointer remains valid for as long /// as the returned `Deferred` exists and that no references to the instance exist when the [Deferred] /// is constructed. If the `Deferred` refers to a shared memory (mapped) region which may be modified somehow /// (e.g. by other threads or processes), then it is also the caller's reponsibility never to call /// the safe methods [`<Deferred as Deref>::deref`](core::ops::Deref::deref) or /// [`<Deferred as DerefMut>::deref_mut`](core::ops::DerefMut::deref_mut). This would alias the entire memory /// region and is only safe when there are no other writers and readers, respectively. /// /// # Caveat /// The lifetime for the returned `Deferred` is inferred from its usage. To prevent accidental misuse, /// it's suggested to tie the lifetime to whichever source lifetime is safe in the context, such as /// by providing a helper function taking the lifetime of a host value, or by explicit annotation. /// /// ``` /// use deferred_reference::Deferred; /// /// SAFETY: `Buffer` may only be implemented on valid smart-pointers which don't own /// /// SAFETY: the memory. The smart pointer must also point to fully initialized memory. /// pub unsafe trait Buffer { /// fn as_ptr(&self) -> *mut u8; /// fn len(&self) -> usize; /// } /// /// The lifetime of the returned [Deferred] is bound to the lifetime of the /// /// mutable borrow of smart pointer `T` through the explicit lifetime 'a. /// fn defer_mut<'a, T>(buffer: &'a mut T) -> Deferred<&'a mut [u8]> /// where /// T: Buffer /// { /// let slice_ptr = core::ptr::slice_from_raw_parts_mut(buffer.as_ptr(), buffer.len()); /// // SAFETY: this is safe because `Deferred` occupies the only mutable reference /// // SAFETY: to the smart pointer `T` for the duration of lifetime 'a, which means /// // SAFETY: no other callers can safely obtain a mutable reference at the same time. /// unsafe { Deferred::from_raw_mut(slice_ptr) } /// } /// ``` /// The documentation of [DeferMut](crate::DeferMut) contains some additional examples of how to properly call /// [Deferred::from_raw_mut]. pub unsafe fn from_raw_mut(ptr: *mut T) -> Deferred<&'a mut T> { Self { ptr: NonNull::new_unchecked(ptr as *mut T), } } } /// # Methods available on all deferred references impl<T> Deferred<T> where T: Reference, { /// Obtains an immutable pointer to where the deferred reference points. /// This pointer can be a thin pointer if `T` is sized or a fat pointer /// otherwise. pub fn as_ptr(&self) -> *const T::Target { self.ptr.as_ptr() as *const _ } /// Unsizes the deferred reference. This method is experimental. /// /// # Example /// ``` /// use deferred_reference::{Defer, DeferMut, Deferred}; /// use core::cell::UnsafeCell; /// let mut buffer = UnsafeCell::new([0u8; 1024]); /// let deferred_array /* : Deferred<&[u8; 1024]> */ = buffer.defer(); /// let deferred_slice: Deferred<&[u8]> = deferred_array.unsize(); // needs an explicit type /// let deferred_array_mut /* : Deferred<&mut [u8; 1024]> */ = unsafe { buffer.defer_mut() }; /// let deferred_slice_mut: Deferred<&mut [u8]> = deferred_array_mut.unsize(); /// ``` /// /// # Unstable /// This method requires the unstable `Cargo.toml` feature `unstable` or `coerce_unsized` to be enabled. /// This method may become stable once the `coerce_unsized` feature lands in stable Rust, see /// <https://github.com/rust-lang/rust/issues/27732>. For a stable alternative, you may also use /// use the [From]/[Into] traits which are implemented on [Deferred] for converting deferred arrays to /// deferred slices. #[cfg(feature = "coerce_unsized")] pub fn unsize<U>(self) -> Deferred<U> where U: Reference, NonNull<T::Target>: core::ops::CoerceUnsized<NonNull<U::Target>>, // requires #![feature(coerce_unsized)]` { Deferred { ptr: self.ptr, } } } /// # Methods available for all deferred _mutable_ references impl<'a, T: ?Sized> Deferred<&'a mut T> { /// Obtains an mutable pointer to where the deferred reference points. /// This pointer can be a thin pointer if `T` is sized or a fat pointer /// otherwise. pub fn as_mut_ptr(&self) -> *mut T { self.ptr.as_ptr() } /// Make a copy of this mutable `Deferred<&'a mut T>`. The copy will have the same lifetime as `'a`. /// /// # Safety /// This method can be very unsafe. Cloning a mutable deferred reference will let you safely dereference it mutably /// afterwards (e.g. through [`<Deferred<&mut T> as DerefMut>::deref_mut`](core::ops::DerefMut::deref_mut)) from several /// distinct places simultaneously and this could lead to aliased mutable references which is then instant undefined behavior. /// That is why this function is marked as unsafe. Cloning a `Deferred<&mut T>` is not undefined behavior, because this is a /// smart pointer and not an actual live reference. Be very careful not to accidentally create mutable aliased references through /// dereferencing any `Deferred<&mut T>` after calling [`Deferred::clone_unchecked`](Deferred::clone_unchecked) on it!!! /// Calling [`<Deferred as Clone>::clone`](Clone::clone) on immutable deferred references (i.e. `Deferred<&T>`) is entirely safe /// (and all `Deferred<&T>` also implement the [Copy] trait). pub unsafe fn clone_unchecked(&self) -> Self { // SAFETY: calling `from_raw_parts_mut` is safe because the invariant of [Deferred] is respected. // SAFETY: still this method is unsafe by itself, see the Safety notes. Deferred::from_raw_mut(self.as_mut_ptr()) } /// Convert this deferred mutable reference into a deferred immutable reference. /// /// # Example /// ``` /// use deferred_reference::{DeferMut, Deferred}; /// use core::cell::UnsafeCell; /// let buffer = UnsafeCell::new([0u8; 1024]); /// // SAFETY: this is safe, because this is the only deferred reference we create: /// let deferred_mut: Deferred<&mut [u8; 1024]> = unsafe { buffer.defer_mut() }; /// // which we then convert into a deferred immutable reference: /// let deferred: Deferred<&[u8; 1024]> = deferred_mut.into_ref(); /// ``` pub fn into_ref(self) -> Deferred<&'a T> { self.into() } } #[cfg(test)] mod tests { use core::cell::UnsafeCell; use crate::{Defer, DeferMut, Deferred}; #[test] fn new() { let mut buffer = [0u8; 1024]; let mut deferred = Deferred::from(&mut buffer); //assert_eq!(0, buffer[0]); // cannot borrow `buffer[_]` as immutable because it is also borrowed as mutable assert_eq!(0, deferred[0]); assert_eq!(&mut 0, &mut deferred[0]); let mut deferred2 = unsafe { deferred.clone_unchecked() }; let tmp1: &mut [u8] = &mut deferred[10..20]; // let tmp2 = &mut deferred2[30..40]; tmp1[0] = 42; // UB because `tmp2` creates a new &mut reference // tmp2[0] = 42; // assert_eq!(&mut tmp1[0], &mut tmp2[0]); deferred2[0] = 42; assert_eq!(42, deferred[0]); assert_eq!(42, buffer[0]); } #[test] fn mut_ref_invalidation() { let buffer = UnsafeCell::new([0u8; 1024]); let mut deferred = unsafe { buffer.defer_mut() }; let mut deferred2 = unsafe { deferred.clone_unchecked() }; deferred[10] = 1; // not UB, because mutable reference is temporary deferred2[30] = 1; // not UB, because new mutable reference is created let _tmp1 = &mut deferred[10..20]; let tmp2 = &mut deferred2[30..40]; // tmp1[0] = 42; // UB because `tmp2` creates a new &mut reference tmp2[0] = 42; // assert_eq!(&mut tmp1[0], &mut tmp2[0]); // UB } /// Tests whether [Deferred] can be casted to pointers of other types without UB #[test] fn cast_to_ptr() { let mut buffer = UnsafeCell::new([0u8; 1024]); buffer.get_mut()[0] = 1; { let deferred = buffer.defer(); let ptr = unsafe { *(core::ptr::addr_of!(deferred) as *const *const [u8; 1024]) }; assert_eq!(*deferred, unsafe { *ptr }); } { let deferred = unsafe { buffer.defer_mut() }; let ptr = unsafe { *(core::ptr::addr_of!(deferred) as *const *mut [u8; 1024]) }; assert_eq!(*deferred, unsafe { *ptr }); } { let mut deferred = unsafe { buffer.defer_mut() }; let ptr = unsafe { *(core::ptr::addr_of_mut!(deferred) as *mut *mut [u8; 1024]) }; assert_eq!(*deferred, unsafe { *ptr }); } } /// Tests that niche size optimization works. #[test] fn size_of() { assert_eq!(core::mem::size_of::<Deferred<&[u8]>>(), core::mem::size_of::<Option<Deferred<&[u8]>>>()) } /// Tests that pointers point to the same address. #[test] fn as_ptr() { let buffer = UnsafeCell::new([0u8; 1024]); let deferred = buffer.defer(); assert_eq!(deferred.as_ptr() as usize, buffer.get() as usize); } /// Tests that mutable pointers point to the same address. #[test] fn as_mut_ptr() { let buffer = UnsafeCell::new([0u8; 1024]); let deferred = unsafe { buffer.defer_mut() }; assert_eq!(deferred.as_mut_ptr() as usize, buffer.get() as usize); } }