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}