deferred_reference/
defer.rs

1use core::cell::UnsafeCell;
2
3use crate::Reference;
4
5use super::Deferred;
6
7/// An unsafe macro to create a deferred immutable reference (i.e. a [`Deferred<&T>`](Deferred)) to a place,
8/// without creating an intermediate reference. See the documentation at [Deferred] explaining the
9/// [constructors for deferred immutable references](Deferred#constructors-for-deferred-immutable-references)
10/// for safe alternatives.
11///
12/// Use of this macro is not recommended, because it's a lot more unsafe than obtaining a `Deferred<&T>` through
13/// a type that implements the [Defer] trait. Use [`Defer::defer`](Defer::defer) or [`Deferred::from(&T)`](From::from)
14/// for a safe alternative instead.
15///
16/// The only use case for this macro is when you can't create a reference to a place and also can't use [UnsafeCell]
17/// to achieve interior mutability. However, this is a rare case and requires advanced knowledge of unsafe Rust.
18///
19/// # Example
20/// ```
21/// #[macro_use]
22/// extern crate deferred_reference;
23/// use deferred_reference::Deferred;
24/// fn main() {
25///     let buffer = [0u8; 1024];
26///     // works for deferred references to slices:
27///     let deferred: Deferred<&[u8]> =  unsafe { defer!(buffer) };
28///     assert_eq!(buffer[0], deferred[0]);
29///     // and works also for deferred references to arrays:
30///     let deferred: Deferred<&[u8; 1024]> =  unsafe { defer!(buffer) };
31///     assert_eq!(buffer[0], deferred[0]);
32/// }
33/// ```
34///
35/// # Safety
36/// This macro is very unsafe and should only be used if there is no other safe way to obtain a deferred reference.
37/// See the [Defer] trait for the preferred way to create an immutable deferred reference. When using this
38/// macro, the caller must uphold the following guarantees:
39/// * When dereferencing the [Deferred], the Rust alias rules must be upheld at all times. E.g. don't create mutable and
40///   immutable references to the same place (these may not partially overlap either).
41/// * The place must be properly aligned and initialized.
42/// * The caller must ensure that the invariant of the returned [Deferred] is upheld.
43/// * The place must not be moved or dropped for as long as the returned [Deferred] is in use.
44/// * No mutable references to the place may be created as long as the [Deferred] is in use. This will invalidate the [Deferred].
45///
46/// Here is an example that will cause undefined behavior to illustrate how unsafe this macro is.
47/// The compiler will happilly compile this and not give any warning:
48/// ```no_run
49/// #[macro_use]
50/// extern crate deferred_reference;
51/// fn main() {
52///     let mut buffer = [0u8; 1024];
53///     let deferred = unsafe { defer!(buffer) };
54///     buffer[0] = 42; // this implicitly creates a temporary mutable reference to `buffer`
55///     // `deferred` is now invalidated 
56///     // this is undefined behavior, even though the lifetimes of
57///     // the immutable and mutable reference don't overlap:
58///     assert_eq!(buffer[0], deferred[0]);
59/// }
60/// ```
61/// This kind of pitfalls are not possible with instances of `Deferred<&T>` obtained through [Defer::defer],
62/// because then the Rust compiler can detect these violations due to the bounded lifetime of
63/// `Deferred<&T>`. In this case the compiler will warn you before-hand:
64/// ```compile_fail
65/// use deferred_reference::Defer;
66/// use core::cell::UnsafeCell;
67/// let mut buffer = UnsafeCell::new([0u8; 1024]);
68/// let deferred = buffer.defer(); // note the absence of the unsafe block!
69/// // the next line will cause the compilation to fail with the error:
70/// // "cannot borrow `buffer` as mutable because it is also borrowed as immutable"
71/// buffer.get_mut()[0] = 42;
72/// assert_eq!(0, deferred[0]); // assures `deferred` is in use until here
73/// ```
74///
75/// # Caveat
76/// The lifetime for the returned [Deferred] is inferred from its usage. To prevent accidental misuse,
77/// it's suggested to tie the lifetime to whichever source lifetime is safe in the context, such as
78/// by providing a helper function taking the lifetime of a host value, or by explicit annotation.
79/// However, this can get very complicated and very unsafe real fast, here is an example of how this
80/// could end up looking like (accompanied by the obligatory "*do not try this at home, kids!*"):
81/// ```compile_fail
82/// #[macro_use]
83/// extern crate deferred_reference;
84/// use deferred_reference::Deferred;
85/// use core::marker::PhantomData;
86/// fn shorten_lifetime<'a, 'b: 'a>(a: &'a PhantomData<[u8]>, b: Deferred<&'b [u8]>)
87///     -> (&'a PhantomData<[u8]>, Deferred<&'a [u8]>)
88/// {
89///     // SAFETY: shortening the lifetime of 'b to 'a is always safe
90///     unsafe { core::mem::transmute((a, b)) }
91/// }
92/// fn borrow_mut<'a>(_accountant: &'a mut PhantomData<[u8]>, borrow_mut: &'a mut [u8])
93///     -> &'a mut [u8]
94/// {
95///     borrow_mut
96/// }
97/// macro_rules! get_deferred {
98///     ($accountant:ident, $place:expr) => {
99///         shorten_lifetime(&$accountant, defer!($place)).1
100///     };
101/// }
102/// macro_rules! borrow_mut {
103///     ($accountant:ident, $place:expr) => {
104///         borrow_mut(&mut $accountant, &mut $place)
105///     };
106/// }
107/// fn main() {
108///     let mut buffer = [0u8; 1024];
109///     // the `accountant` acts as a compile-time semaphore through the Rust borrow rules.
110///     let mut accountant = PhantomData::<[u8]>;
111///     // SAFETY: we promise to only use the `get_deferred` and `borrow_mut` macros.
112///     // SAFETY: this is safe, because we don't take out explicit borrows like
113///     // SAFETY: `&mut buffer` which are not tracked by our `accountant`.
114///     let deferred: Deferred<&[u8]> = unsafe { get_deferred!(accountant, buffer) };
115///     assert_eq!(0, deferred[0]);
116///     // the next line will give an error at compile-time:
117///     // "cannot borrow `accountant` as mutable because it is also borrowed as immutable"
118///     let ref_mut: &mut [u8] = borrow_mut!(accountant, buffer); // mutably borrows
119///     assert_eq!(0, deferred[0]); // asserts that `deferred` is in use until here
120/// }
121/// ```
122#[macro_export]
123macro_rules! defer {
124    ($place:expr) => {
125        $crate::Deferred::from_raw(core::ptr::addr_of!($place))
126    };
127}
128
129/// The [Defer] trait offers easy access to deferred immutable references
130/// to types that implement [Defer].
131///
132/// # Examples
133/// ```
134/// use deferred_reference::{Defer, Deferred};
135/// use core::cell::UnsafeCell;
136///
137/// // Defer is implemented by default for any `UnsafeCell` holding an array or a slice:
138/// let buffer = UnsafeCell::new([0u8; 1024]);
139/// let deferred: Deferred<&[u8; 1024]> = buffer.defer();
140/// // A deferred reference to an *array* can be unsized to a deferred reference to a *slice*:
141/// let deferred_unsized: Deferred<&[u8]> = deferred.into();
142/// // Dereferencing will create an actual reference `&[u8]`:
143/// assert_eq!(*deferred, *deferred_unsized);
144/// assert_eq!(*deferred, &[0u8; 1024][..]);
145///
146/// // Even though this crate is `#![no_std]`, it works with heap allocated contents as well:
147/// let buffer = Box::new(UnsafeCell::new([0u8; 1024]));
148/// let deferred /* : Deferred<&[u8; 1024]> */ = buffer.defer(); // omitting the type is okay
149/// let deferred_unsized: Deferred<&[u8]> = deferred.into(); // unsize needs explicit type
150/// // Dereferencing will create an actual reference `&[u8]`:
151/// assert_eq!(*deferred, *deferred_unsized);
152/// assert_eq!(*deferred, &[0u8; 1024][..]);
153/// ```
154///
155/// # Why is `Defer` not implemented for all types?
156/// The [Defer] trait comes implemented for all [`UnsafeCell<T: ?Sized>`](core::cell::UnsafeCell),
157/// but it is not implemented for all types `T: ?Sized` which are not wrapped in an [UnsafeCell].
158/// This is by design, because calling the `Defer::defer(&self)` method will take out an immutable reference
159/// for as long as the returned [Deferred] is in use. In other words, this is not a deferrred
160/// immutable reference, but an actual immutable reference to the underlying type. As long as this
161/// immutable reference is in use, it is not allowed to create additional (deferred) mutable references
162/// due to the Rust borrowing rules, unless the type is wrapped in an [UnsafeCell], which allows for
163/// interior mutability (in fact this is the only way that Rust supports interior mutability).
164/// If you don't intend to mutate the underlying type, then there is no use-case for [Defer]
165/// and you're better off using an immutable reference `&T` instead of a `Deferred<&T>`.
166/// If you do intend to mutate the underlying type, but have a good reason not to use [UnsafeCell],
167/// then you may do so using the unsafe [`defer!`](macro@defer) and [`defer_mut!`](macro@defer_mut) macros.
168/// However, use of these macros is not recommend and you should probably only use these if you know what you're
169/// doing, because the lifetime of the [Deferred] returned by these macros is unbounded and the burden of
170/// managing the lifetimes falls on the implementor. Note that there are also
171/// [other (safe) ways to construct a deferred immutable reference](Deferred#constructors-for-deferred-immutable-references),
172/// see the documentation at [Deferred] for more information on how to do this.
173pub trait Defer {
174    /// The type that the deferred reference points to.
175    type Target: ?Sized;
176    /// Obtain a deferred immutable reference to a [Defer::Target].
177    fn defer(&self) -> Deferred<&Self::Target>;
178}
179
180impl<T: ?Sized> Defer for UnsafeCell<T> {
181    type Target = T;
182    fn defer(&self) -> Deferred<&T> {
183        unsafe {
184            Deferred::from_raw(self.get() as *const _)
185        }
186    }
187}
188
189impl<T: Reference> Defer for Deferred<T> {
190    type Target = T::Target;
191
192    fn defer(&self) -> Deferred<&Self::Target> {
193        // SAFETY: Deferred (i.e. Self) already holds up the invariant, so this is safe.
194        // SAFETY: this yields an almost identical Deferred, except it has a shorter lifetime
195        // SAFETY: (it takes the lifetime of `&self` instead of from `T`)
196        unsafe {
197            Deferred::from_raw(self.as_ptr())
198        }
199    }
200}
201
202#[cfg(test)]
203mod tests {
204    mod defer_macro {
205        use core::marker::PhantomData;
206
207        use crate::Deferred;
208
209        #[test]
210        fn call_macro() {
211            let buffer = [1u8; 1024];
212            let deferred = unsafe { defer!(buffer) };
213            assert_eq!(buffer[0], deferred[0]);
214        }
215        // /// this triggers UB in miri, because deferred gets invalidated
216        // #[test]
217        // fn example_ub() {
218        //     let mut buffer = [2u8; 1024];
219        //     let deferred = unsafe { defer!(buffer) };
220        //     // this is undefined behavior:
221        //     buffer[0] = 42; // because this implicitly creates a temporary mutable reference
222        //     assert_eq!(buffer[0], deferred[0]);
223        // }
224        
225        // /// this is also not possible, Rust detects the mutable borrow:
226        // /// cannot borrow `buffer` as immutable because it is also borrowed as mutable
227        // #[test]
228        // fn assert_no_reference_created() {
229        //     let mut buffer = [2u8; 1024];
230        //     let mut_ref = &mut buffer;
231        //     // next line errors: cannot borrow `buffer` as immutable because it is also borrowed as mutable
232        //     let deferred = unsafe { defer!(buffer) };
233        //     assert_eq!(2, mut_ref[0]);
234        //     assert_eq!(buffer[0], deferred[0]);
235        // }
236
237        fn shorten_lifetime<'a, 'b: 'a>(a: &'a PhantomData<[u8]>, b: Deferred<&'b [u8]>)
238            -> (&'a PhantomData<[u8]>, Deferred<&'a [u8]>) {
239            // SAFETY: shortening the lifetime of 'b to 'a is always safe
240            unsafe { core::mem::transmute((a, b)) }
241        }
242
243        fn borrow_mut<'a>(_accountant: &'a mut PhantomData<[u8]>, borrow_mut: &'a mut [u8]) -> &'a mut [u8] {
244            borrow_mut
245        }
246
247        macro_rules! get_deferred {
248            ($accountant:ident, $place:expr) => {
249                shorten_lifetime(&$accountant, defer!($place)).1
250            };
251        }
252
253        macro_rules! borrow_mut {
254            ($accountant:ident, $place:expr) => {
255                borrow_mut(&mut $accountant, &mut $place)
256            };
257        }
258        #[test]
259        fn bounded_lifetime() {
260            let mut buffer = [0u8; 1024];
261            let mut accountant = PhantomData::<[u8]>;
262            let deferred: Deferred<&[u8]> = unsafe { get_deferred!(accountant, buffer) };
263            assert_eq!(0, deferred[0]);
264            let ref_mut: &mut [u8] = borrow_mut!(accountant, buffer);
265            // assert_eq!(0, deferred[0]);
266            assert_eq!(0, ref_mut[0]);
267        }
268    }
269
270    mod defer_trait {
271        use alloc::boxed::Box;
272        use core::cell::UnsafeCell;
273        use crate::{Defer, Deferred};
274
275        #[test]
276        fn doctest1() {
277            // Defer is implemented by default for any `UnsafeCell` holding an array or a slice:
278            let buffer = UnsafeCell::new([0u8; 1024]);
279            let deferred: Deferred<&[u8; 1024]> = buffer.defer();
280            // A deferred reference to an *array* can be unsized to a deferred reference to a *slice*:
281            let deferred_unsized: Deferred<&[u8]> = deferred.into();
282            // Dereferencing will create an actual reference `&[u8]`:
283            assert_eq!(*deferred, *deferred_unsized);
284            assert_eq!(*deferred, &[0u8; 1024][..]);
285            
286            // Even though this crate is `#![no_std]`, it works with heap allocated contents as well:
287            let buffer = Box::new(UnsafeCell::new([0u8; 1024]));
288            let deferred /* : Deferred<&[u8; 1024]> */ = buffer.defer(); // omitting the type is okay
289            let deferred_unsized: Deferred<&[u8]> = deferred.into(); // unsize needs explicit type
290            // Dereferencing will create an actual reference `&[u8]`:
291            assert_eq!(*deferred, *deferred_unsized);
292            assert_eq!(*deferred, &[0u8; 1024][..]);
293        }
294    }
295}