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
use core::cell::UnsafeCell; use crate::Reference; use super::Deferred; /// An unsafe macro to create a deferred immutable reference (i.e. a [`Deferred<&T>`](Deferred)) to a place, /// without creating an intermediate reference. See the documentation at [Deferred] explaining the /// [constructors for deferred immutable references](Deferred#constructors-for-deferred-immutable-references) /// for safe alternatives. /// /// Use of this macro is not recommended, because it's a lot more unsafe than obtaining a `Deferred<&T>` through /// a type that implements the [Defer] trait. Use [`Defer::defer`](Defer::defer) or [`Deferred::from(&T)`](From::from) /// for a safe alternative instead. /// /// The only use case for this macro is when you can't create a reference to a place and also can't use [UnsafeCell] /// to achieve interior mutability. However, this is a rare case and requires advanced knowledge of unsafe Rust. /// /// # Example /// ``` /// #[macro_use] /// extern crate deferred_reference; /// use deferred_reference::Deferred; /// fn main() { /// let buffer = [0u8; 1024]; /// // works for deferred references to slices: /// let deferred: Deferred<&[u8]> = unsafe { defer!(buffer) }; /// assert_eq!(buffer[0], deferred[0]); /// // and works also for deferred references to arrays: /// let deferred: Deferred<&[u8; 1024]> = unsafe { defer!(buffer) }; /// assert_eq!(buffer[0], deferred[0]); /// } /// ``` /// /// # Safety /// This macro is very unsafe and should only be used if there is no other safe way to obtain a deferred reference. /// See the [Defer] trait for the preferred way to create an immutable deferred reference. When using this /// macro, the caller must uphold the following guarantees: /// * When dereferencing the [Deferred], the Rust alias rules must be upheld at all times. E.g. don't create mutable and /// immutable references to the same place (these may not partially overlap either). /// * The place must be properly aligned and initialized. /// * The caller must ensure that the invariant of the returned [Deferred] is upheld. /// * The place must not be moved or dropped for as long as the returned [Deferred] is in use. /// * No mutable references to the place may be created as long as the [Deferred] is in use. This will invalidate the [Deferred]. /// /// Here is an example that will cause undefined behavior to illustrate how unsafe this macro is. /// The compiler will happilly compile this and not give any warning: /// ```no_run /// #[macro_use] /// extern crate deferred_reference; /// fn main() { /// let mut buffer = [0u8; 1024]; /// let deferred = unsafe { defer!(buffer) }; /// buffer[0] = 42; // this implicitly creates a temporary mutable reference to `buffer` /// // `deferred` is now invalidated /// // this is undefined behavior, even though the lifetimes of /// // the immutable and mutable reference don't overlap: /// assert_eq!(buffer[0], deferred[0]); /// } /// ``` /// This kind of pitfalls are not possible with instances of `Deferred<&T>` obtained through [Defer::defer], /// because then the Rust compiler can detect these violations due to the bounded lifetime of /// `Deferred<&T>`. In this case the compiler will warn you before-hand: /// ```compile_fail /// use deferred_reference::Defer; /// use core::cell::UnsafeCell; /// let mut buffer = UnsafeCell::new([0u8; 1024]); /// let deferred = buffer.defer(); // note the absence of the unsafe block! /// // the next line will cause the compilation to fail with the error: /// // "cannot borrow `buffer` as mutable because it is also borrowed as immutable" /// buffer.get_mut()[0] = 42; /// assert_eq!(0, deferred[0]); // assures `deferred` is in use until here /// ``` /// /// # 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. /// However, this can get very complicated and very unsafe real fast, here is an example of how this /// could end up looking like (accompanied by the obligatory "*do not try this at home, kids!*"): /// ```compile_fail /// #[macro_use] /// extern crate deferred_reference; /// use deferred_reference::Deferred; /// use core::marker::PhantomData; /// fn shorten_lifetime<'a, 'b: 'a>(a: &'a PhantomData<[u8]>, b: Deferred<&'b [u8]>) /// -> (&'a PhantomData<[u8]>, Deferred<&'a [u8]>) /// { /// // SAFETY: shortening the lifetime of 'b to 'a is always safe /// unsafe { core::mem::transmute((a, b)) } /// } /// fn borrow_mut<'a>(_accountant: &'a mut PhantomData<[u8]>, borrow_mut: &'a mut [u8]) /// -> &'a mut [u8] /// { /// borrow_mut /// } /// macro_rules! get_deferred { /// ($accountant:ident, $place:expr) => { /// shorten_lifetime(&$accountant, defer!($place)).1 /// }; /// } /// macro_rules! borrow_mut { /// ($accountant:ident, $place:expr) => { /// borrow_mut(&mut $accountant, &mut $place) /// }; /// } /// fn main() { /// let mut buffer = [0u8; 1024]; /// // the `accountant` acts as a compile-time semaphore through the Rust borrow rules. /// let mut accountant = PhantomData::<[u8]>; /// // SAFETY: we promise to only use the `get_deferred` and `borrow_mut` macros. /// // SAFETY: this is safe, because we don't take out explicit borrows like /// // SAFETY: `&mut buffer` which are not tracked by our `accountant`. /// let deferred: Deferred<&[u8]> = unsafe { get_deferred!(accountant, buffer) }; /// assert_eq!(0, deferred[0]); /// // the next line will give an error at compile-time: /// // "cannot borrow `accountant` as mutable because it is also borrowed as immutable" /// let ref_mut: &mut [u8] = borrow_mut!(accountant, buffer); // mutably borrows /// assert_eq!(0, deferred[0]); // asserts that `deferred` is in use until here /// } /// ``` #[macro_export] macro_rules! defer { ($place:expr) => { $crate::Deferred::from_raw(core::ptr::addr_of!($place)) }; } /// The [Defer] trait offers easy access to deferred immutable references /// to types that implement [Defer]. /// /// # Examples /// ``` /// use deferred_reference::{Defer, Deferred}; /// use core::cell::UnsafeCell; /// /// // Defer is implemented by default for any `UnsafeCell` holding an array or a slice: /// let buffer = UnsafeCell::new([0u8; 1024]); /// let deferred: Deferred<&[u8; 1024]> = buffer.defer(); /// // A deferred reference to an *array* can be unsized to a deferred reference to a *slice*: /// let deferred_unsized: Deferred<&[u8]> = deferred.into(); /// // Dereferencing will create an actual reference `&[u8]`: /// assert_eq!(*deferred, *deferred_unsized); /// assert_eq!(*deferred, &[0u8; 1024][..]); /// /// // Even though this crate is `#![no_std]`, it works with heap allocated contents as well: /// let buffer = Box::new(UnsafeCell::new([0u8; 1024])); /// let deferred /* : Deferred<&[u8; 1024]> */ = buffer.defer(); // omitting the type is okay /// let deferred_unsized: Deferred<&[u8]> = deferred.into(); // unsize needs explicit type /// // Dereferencing will create an actual reference `&[u8]`: /// assert_eq!(*deferred, *deferred_unsized); /// assert_eq!(*deferred, &[0u8; 1024][..]); /// ``` /// /// # Why is `Defer` not implemented for all types? /// The [Defer] trait comes implemented for all [`UnsafeCell<T: ?Sized>`](core::cell::UnsafeCell), /// but it is not implemented for all types `T: ?Sized` which are not wrapped in an [UnsafeCell]. /// This is by design, because calling the `Defer::defer(&self)` method will take out an immutable reference /// for as long as the returned [Deferred] is in use. In other words, this is not a deferrred /// immutable reference, but an actual immutable reference to the underlying type. As long as this /// immutable reference is in use, it is not allowed to create additional (deferred) mutable references /// due to the Rust borrowing rules, unless the type is wrapped in an [UnsafeCell], which allows for /// interior mutability (in fact this is the only way that Rust supports interior mutability). /// If you don't intend to mutate the underlying type, then there is no use-case for [Defer] /// and you're better off using an immutable reference `&T` instead of a `Deferred<&T>`. /// If you do intend to mutate the underlying type, but have a good reason not to use [UnsafeCell], /// then you may do so using the unsafe [`defer!`](macro@defer) and [`defer_mut!`](macro@defer_mut) macros. /// However, use of these macros is not recommend and you should probably only use these if you know what you're /// doing, because the lifetime of the [Deferred] returned by these macros is unbounded and the burden of /// managing the lifetimes falls on the implementor. Note that there are also /// [other (safe) ways to construct a deferred immutable reference](Deferred#constructors-for-deferred-immutable-references), /// see the documentation at [Deferred] for more information on how to do this. pub trait Defer { /// The type that the deferred reference points to. type Target: ?Sized; /// Obtain a deferred immutable reference to a [Defer::Target]. fn defer(&self) -> Deferred<&Self::Target>; } impl<T: ?Sized> Defer for UnsafeCell<T> { type Target = T; fn defer(&self) -> Deferred<&T> { unsafe { Deferred::from_raw(self.get() as *const _) } } } impl<T: Reference> Defer for Deferred<T> { type Target = T::Target; fn defer(&self) -> Deferred<&Self::Target> { // SAFETY: Deferred (i.e. Self) already holds up the invariant, so this is safe. // SAFETY: this yields an almost identical Deferred, except it has a shorter lifetime // SAFETY: (it takes the lifetime of `&self` instead of from `T`) unsafe { Deferred::from_raw(self.as_ptr()) } } } #[cfg(test)] mod tests { mod defer_macro { use core::marker::PhantomData; use crate::Deferred; #[test] fn call_macro() { let buffer = [1u8; 1024]; let deferred = unsafe { defer!(buffer) }; assert_eq!(buffer[0], deferred[0]); } // /// this triggers UB in miri, because deferred gets invalidated // #[test] // fn example_ub() { // let mut buffer = [2u8; 1024]; // let deferred = unsafe { defer!(buffer) }; // // this is undefined behavior: // buffer[0] = 42; // because this implicitly creates a temporary mutable reference // assert_eq!(buffer[0], deferred[0]); // } // /// this is also not possible, Rust detects the mutable borrow: // /// cannot borrow `buffer` as immutable because it is also borrowed as mutable // #[test] // fn assert_no_reference_created() { // let mut buffer = [2u8; 1024]; // let mut_ref = &mut buffer; // // next line errors: cannot borrow `buffer` as immutable because it is also borrowed as mutable // let deferred = unsafe { defer!(buffer) }; // assert_eq!(2, mut_ref[0]); // assert_eq!(buffer[0], deferred[0]); // } fn shorten_lifetime<'a, 'b: 'a>(a: &'a PhantomData<[u8]>, b: Deferred<&'b [u8]>) -> (&'a PhantomData<[u8]>, Deferred<&'a [u8]>) { // SAFETY: shortening the lifetime of 'b to 'a is always safe unsafe { core::mem::transmute((a, b)) } } fn borrow_mut<'a>(_accountant: &'a mut PhantomData<[u8]>, borrow_mut: &'a mut [u8]) -> &'a mut [u8] { borrow_mut } macro_rules! get_deferred { ($accountant:ident, $place:expr) => { shorten_lifetime(&$accountant, defer!($place)).1 }; } macro_rules! borrow_mut { ($accountant:ident, $place:expr) => { borrow_mut(&mut $accountant, &mut $place) }; } #[test] fn bounded_lifetime() { let mut buffer = [0u8; 1024]; let mut accountant = PhantomData::<[u8]>; let deferred: Deferred<&[u8]> = unsafe { get_deferred!(accountant, buffer) }; assert_eq!(0, deferred[0]); let ref_mut: &mut [u8] = borrow_mut!(accountant, buffer); // assert_eq!(0, deferred[0]); assert_eq!(0, ref_mut[0]); } } mod defer_trait { use alloc::boxed::Box; use core::cell::UnsafeCell; use crate::{Defer, Deferred}; #[test] fn doctest1() { // Defer is implemented by default for any `UnsafeCell` holding an array or a slice: let buffer = UnsafeCell::new([0u8; 1024]); let deferred: Deferred<&[u8; 1024]> = buffer.defer(); // A deferred reference to an *array* can be unsized to a deferred reference to a *slice*: let deferred_unsized: Deferred<&[u8]> = deferred.into(); // Dereferencing will create an actual reference `&[u8]`: assert_eq!(*deferred, *deferred_unsized); assert_eq!(*deferred, &[0u8; 1024][..]); // Even though this crate is `#![no_std]`, it works with heap allocated contents as well: let buffer = Box::new(UnsafeCell::new([0u8; 1024])); let deferred /* : Deferred<&[u8; 1024]> */ = buffer.defer(); // omitting the type is okay let deferred_unsized: Deferred<&[u8]> = deferred.into(); // unsize needs explicit type // Dereferencing will create an actual reference `&[u8]`: assert_eq!(*deferred, *deferred_unsized); assert_eq!(*deferred, &[0u8; 1024][..]); } } }