fortify/
lib.rs

1#![warn(missing_docs)]
2//! This crate provides the [`Fortify`] wrapper type. When used with a borrowing type (i.e. a type
3//! with a lifetime parameter) it allows values of that type to reference arbitrary data owned by
4//! the `Fortify` itself.
5//!
6//! # Example
7//! ```
8//! use fortify::*;
9//!
10//! // Define a borrowing type. The `Lower` trait specifies that it is covariant in its first
11//! // lifetime parameter.
12//! #[derive(Lower)]
13//! struct Example<'a> {
14//!    a: &'a i32,
15//!    b: &'a mut i32,
16//! }
17//!
18//! // Construct a fortified value that makes an "external" reference to `a` and an "internal"
19//! // reference to `b`, which is owned by the Fortify.
20//! let a = 1;
21//! let mut example: Fortify<Example> = fortify! {
22//!     let mut b = 1;
23//!     b += 1;
24//!     yield Example {
25//!         a: &a,
26//!         b: &mut b
27//!     };
28//! };
29//!
30//! // Use `with_mut` for general mutable access to the wrapped value. Note that the reference
31//! // to `b` is still valid even though `b` is not in scope in this block.
32//! example.with_mut(|example| {
33//!     assert_eq!(*example.a, 1);
34//!     assert_eq!(*example.b, 2);
35//!     *example.b += 1;
36//!     assert_eq!(*example.b, 3);
37//! });
38//! ```
39extern crate self as fortify;
40mod lower;
41
42pub use fortify_derive::*;
43pub use lower::*;
44use std::future::Future;
45use std::mem::{transmute_copy, ManuallyDrop, MaybeUninit};
46use std::pin::Pin;
47use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
48
49/// Wraps a value of type `T` and allows it to reference arbitrary supplementary data owned by the
50/// [`Fortify`]. This can be used to effectively convert a borrowing type into an owning type.
51///
52/// # Example
53/// ```
54/// use fortify::*;
55/// let example: Fortify<&'static str> = fortify! {
56///     let mut str = String::new();
57///     str.push_str("Foo");
58///     str.push_str("Bar");
59///     yield str.as_str();
60/// };
61/// example.with_ref(|s| assert_eq!(s, &"FooBar"));
62/// assert_eq!(example.borrow(), &"FooBar");
63/// ```
64pub struct Fortify<T> {
65    value: ManuallyDrop<T>,
66    data_raw: *mut (),
67    data_drop_fn: unsafe fn(*mut ()),
68}
69
70impl<T> Fortify<T> {
71    /// Directly constructs a [`Fortify`] wrapper over the given value.
72    pub fn new(value: T) -> Self {
73        Self {
74            value: ManuallyDrop::new(value),
75            data_raw: std::ptr::null_mut(),
76            data_drop_fn: drop_nop,
77        }
78    }
79}
80
81impl<'a, T: Refers<'a>> Fortify<T> {
82    /// Creates a [`Fortify`] by explicitly providing its owned data and constructing its value
83    /// from that using a closure. Note that for technical reasons, the constructed value must be
84    /// wrapped in a [`Lowered`] wrapper.
85    ///
86    /// # Example
87    /// ```
88    /// use fortify::{Fortify, Lowered};
89    /// let mut str = String::new();
90    /// str.push_str("Hello");
91    /// let fortified: Fortify<&str> = Fortify::new_dep(str, |s| Lowered::new(s.as_str()));
92    /// assert_eq!(fortified.borrow(), &"Hello");
93    /// ```
94    pub fn new_dep<O: 'a, C>(owned: O, cons: C) -> Self
95    where
96        C: for<'b> FnOnce(&'b mut O) -> Lowered<'b, T>,
97    {
98        Self::new_box_dep(Box::new(owned), cons)
99    }
100
101    /// Creates a [`Fortify`] by explicitly providing its owned data (as a [`Box`]) and
102    /// constructing its value from that using a closure. Note that for technical reasons, the
103    /// constructed value must be wrapped in a [`Lowered`] wrapper.
104    pub fn new_box_dep<O: 'a, C>(owned: Box<O>, cons: C) -> Self
105    where
106        C: for<'b> FnOnce(&'b mut O) -> Lowered<'b, T>,
107    {
108        let owned = Box::into_raw(owned);
109        let value = cons(unsafe { &mut *owned });
110        Self {
111            value: ManuallyDrop::new(value.value),
112            data_raw: owned as *mut (),
113            data_drop_fn: drop_box_from_raw::<O>,
114        }
115    }
116
117    /// Creates a [`Fortify`] by using a [`Future`] to construct the `Fortify`'s value. As soon
118    /// as the `Future` "yields" a value, it will be suspended and become the supplementary data
119    /// for the `Fortify`. This allows the inner value to reference locals defined by the `Future`.
120    ///
121    /// The `Future` must await on [`FortifyYielder::yield_`] and nothing else. Code following the
122    /// await may or may not be executed.
123    ///
124    /// This is a hacky way of taking advantage of rust's code generation for async in order to
125    /// suspend an executing block of code. In the future, when 'generators' is stabilized, this
126    /// would be unnecessary. Therefore, it is recommended to use the [`fortify!`] macro instead.
127    ///
128    /// # Example
129    /// ```
130    /// use fortify::{Fortify, Lowered};
131    /// let external = 1;
132    /// let mut fortified: Fortify<(&i32, &i32)> = Fortify::new_async(|y| async {
133    ///     let internal = 2;
134    ///     y.yield_(Lowered::new((&external, &internal))).await;
135    /// });
136    /// let (external_ref, internal_ref) = *fortified.borrow();
137    /// assert_eq!(*external_ref, 1);
138    /// assert_eq!(*internal_ref, 2);
139    /// ```
140    pub fn new_async<C, F>(cons: C) -> Self
141    where
142        C: 'a + FnOnce(FortifyYielder<T>) -> F,
143        F: 'a + Future<Output = ()>,
144    {
145        let waker = nop_waker();
146        let mut cx = Context::from_waker(&waker);
147        let mut data = FortifyYielderData {
148            value: MaybeUninit::uninit(),
149            tracker: FortifyYielderTracker {
150                cx_ptr: &cx as *const Context as *const (),
151                has_awaited: false,
152            },
153        };
154        let future = Box::into_raw(Box::new(cons(FortifyYielder(&mut data))));
155        match Future::poll(unsafe { Pin::new_unchecked(&mut *future) }, &mut cx) {
156            Poll::Ready(_) => {
157                unsafe { drop_box_from_raw::<F>(future as *mut ()) };
158                panic!("Future must await on FortifyYielder::yield_")
159            }
160            Poll::Pending => {
161                if data.tracker.has_awaited {
162                    Self {
163                        value: ManuallyDrop::new(unsafe {
164                            transmute_copy(data.value.assume_init_ref())
165                        }),
166                        data_raw: future as *mut (),
167                        data_drop_fn: drop_box_from_raw::<F>,
168                    }
169                } else {
170                    unsafe { drop_box_from_raw::<F>(future as *mut ()) };
171                    panic!("Future may only await on FortifyYielder::yield_")
172                }
173            }
174        }
175    }
176}
177
178impl<'a, T: Lower<'a, Target = T>> Fortify<&'a T> {
179    /// Creates a [`Fortify`] by taking ownership of a [`Box`] and wrapping a reference to
180    /// the value inside it.
181    ///
182    /// # Example
183    /// ```
184    /// use fortify::Fortify;
185    /// let value = Box::new(123);
186    /// let mut fortified: Fortify<&i32> = Fortify::new_box_ref(value);
187    /// assert_eq!(**fortified.borrow(), 123);
188    /// assert_eq!(fortified.with_inner(|x| *x), 123);
189    /// ```
190    pub fn new_box_ref(value: Box<T>) -> Self {
191        Self::new_box_dep(value, |inner| Lowered::new(&*inner))
192    }
193}
194
195impl<'a, T: 'a> Fortify<&'a mut T> {
196    /// Creates a [`Fortify`] by taking ownership of a [`Box`] and wrapping a mutable reference to
197    /// the value inside it.
198    ///
199    /// # Example
200    /// ```
201    /// use fortify::Fortify;
202    /// let value = Box::new(123);
203    /// let mut fortified: Fortify<&mut i32> = Fortify::new_box_mut(value);
204    /// fortified.with_mut(|v| **v *= 2);
205    /// assert_eq!(**fortified.borrow(), 246);
206    /// ```
207    pub fn new_box_mut(value: Box<T>) -> Self {
208        Self::new_box_dep(value, |inner| Lowered::new(inner))
209    }
210}
211
212impl<'a, T: Lower<'a>> Fortify<T> {
213    /// Immutably borrows the value inside a [`Fortify`]. For more general access to the wrapped
214    /// value, see [`Fortify::with_ref`] and [`Fortify::with_mut`].
215    #[allow(clippy::should_implement_trait)]
216    // We would like to implement `std::borrow::Borrow`, but it's not possible to specify the
217    // lifetime correctly.
218    pub fn borrow(&'a self) -> &'a <T as Lower<'a>>::Target {
219        let value = &*self.value;
220        unsafe { transmute_copy(&value) }
221    }
222}
223
224impl<T: for<'a> Lower<'a>> Fortify<T> {
225    /// Executes a closure using an immutable reference to the value stored inside this [`Fortify`].
226    ///
227    /// Calls to `with_ref` can typically be replaced with and simplified using `borrow`. This
228    /// method is retained for consistency with `with_mut` and possible support for non-covariant
229    /// types (which can't use `borrow`) in the future.
230    pub fn with_ref<'a, F, R>(&'a self, f: F) -> R
231    where
232        F: for<'b> FnOnce(&'a <T as Lower<'b>>::Target) -> R,
233    {
234        let value = &*self.value;
235        f(unsafe { transmute_copy(&value) })
236    }
237
238    /// Executes a closure using a mutable reference to the value stored inside this [`Fortify`].
239    pub fn with_mut<'a, F, R>(&'a mut self, f: F) -> R
240    where
241        F: for<'b> FnOnce(&'a mut <T as Lower<'b>>::Target) -> R,
242    {
243        let value = &mut *self.value;
244        f(unsafe { transmute_copy(&value) })
245    }
246
247    /// Executes a closure with the value stored inside this [`Fortify`], effectively destructing
248    /// the wrapper.
249    pub fn with_inner<F, R>(self, f: F) -> R
250    where
251        for<'a> <T as Lower<'a>>::Target: Sized,
252        F: for<'a> FnOnce(<T as Lower<'a>>::Target) -> R,
253    {
254        self.split(|inner| (Lowered::new(()), f(Lowered::unwrap(inner))))
255            .1
256    }
257}
258
259impl<'a, T: 'a> Fortify<T> {
260    /// Maps and splits this [`Fortify`] wrapper into a component that references its owned
261    /// data, and a component that doesn't. This is a generalization of both [`Fortify::map`] and
262    /// [`Fortify::with_inner`].
263    ///
264    /// # Example
265    /// ```
266    /// use fortify::*;
267    /// let fortified: Fortify<(&i32, i32)> = fortify! {
268    ///     let x = 12;
269    ///     yield (&x, 15);
270    /// };
271    /// let (x, y) = fortified.split(|inner| (Lowered::new(inner.0), inner.1));
272    /// assert_eq!(**x.borrow(), 12);
273    /// assert_eq!(y, 15);
274    /// ```
275    pub fn split<F, N, R>(mut self, f: F) -> (Fortify<N>, R)
276    where
277        N: Refers<'a>,
278        F: for<'b> FnOnce(Lowered<'b, T>) -> (Lowered<'b, N>, R),
279    {
280        let value = unsafe { ManuallyDrop::take(&mut self.value) };
281        let data_raw = self.data_raw;
282        let data_drop_fn = self.data_drop_fn;
283        std::mem::forget(self);
284        let (value, res) = f(Lowered {
285            value,
286            marker: std::marker::PhantomData,
287        });
288        (
289            Fortify {
290                value: ManuallyDrop::new(value.value),
291                data_raw,
292                data_drop_fn,
293            },
294            res,
295        )
296    }
297
298    /// Constructs a new [`Fortify`] wrapper by applying a mapping function to the value stored
299    /// in this wrapper. The resulting [`Fortify`] will carry the exact same owned data as this
300    /// does.
301    pub fn map<F, N>(self, f: F) -> Fortify<N>
302    where
303        N: Refers<'a>,
304        F: for<'b> FnOnce(Lowered<'b, T>) -> Lowered<'b, N>,
305    {
306        self.split(|inner| (f(inner), ())).0
307    }
308}
309
310/// Indicates that, if this type has a non-trivial implementation of [`Lower`], it references
311/// the lifetime `'a`. Thus, the bound `T: Refers<'a>` can be thought of as the inverse of `T: 'a`.
312///
313/// This is used by various [`Fortify`]-constructing functions to ensure that the resulting
314/// wrapper does not outlive the external references it contains. This will be automatically
315/// implemented for any type that correctly implements [`Lower`].
316pub trait Refers<'a> {}
317
318impl<'a, T: Lower<'a, Target = T>> Refers<'a> for T {}
319
320impl<T> From<T> for Fortify<T> {
321    fn from(value: T) -> Self {
322        Fortify::new(value)
323    }
324}
325
326impl<'a, T: Lower<'a, Target = T>> From<Box<T>> for Fortify<&'a T> {
327    fn from(value: Box<T>) -> Self {
328        Fortify::new_box_ref(value)
329    }
330}
331
332impl<'a, T> From<Box<T>> for Fortify<&'a mut T> {
333    fn from(value: Box<T>) -> Self {
334        Fortify::new_box_mut(value)
335    }
336}
337
338impl<T: Default> Default for Fortify<T> {
339    fn default() -> Self {
340        Fortify::new(T::default())
341    }
342}
343
344impl<T> std::fmt::Debug for Fortify<T>
345where
346    for<'a> T: Lower<'a>,
347    for<'a> <T as Lower<'a>>::Target: std::fmt::Debug,
348{
349    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350        self.borrow().fmt(f)
351    }
352}
353
354impl<T> std::fmt::Display for Fortify<T>
355where
356    for<'a> T: Lower<'a>,
357    for<'a> <T as Lower<'a>>::Target: std::fmt::Display,
358{
359    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
360        self.borrow().fmt(f)
361    }
362}
363
364unsafe impl<'a, T: Lower<'a>> Lower<'a> for Fortify<T>
365where
366    T::Target: Sized,
367{
368    type Target = Fortify<T::Target>;
369}
370
371impl<T: Iterator> Iterator for Fortify<T>
372where
373    for<'a> T: Lower<'a>,
374    for<'a> <T as Lower<'a>>::Target: Iterator<Item = T::Item>,
375{
376    type Item = T::Item;
377    fn next(&mut self) -> Option<Self::Item> {
378        self.with_mut(|inner| inner.next())
379    }
380}
381
382impl<T> Drop for Fortify<T> {
383    fn drop(&mut self) {
384        unsafe {
385            // Value must be dropped before data
386            ManuallyDrop::drop(&mut self.value);
387            (self.data_drop_fn)(self.data_raw);
388        }
389    }
390}
391
392/// Does nothing.
393unsafe fn drop_nop(_: *mut ()) {
394    // Nothing to do here
395}
396
397/// Constructs a box from its raw pointer and then drops it.
398unsafe fn drop_box_from_raw<T>(raw: *mut ()) {
399    // NOTE: It may seem easier to convert to a box and drop it here, but that may trigger UB if
400    // the box contains self-references (which is common with futures). Instead, we'll use the
401    // destruction pattern from https://doc.rust-lang.org/std/boxed/struct.Box.html#method.into_raw
402    std::ptr::drop_in_place(raw as *mut T);
403    let layout = std::alloc::Layout::new::<T>();
404    if layout.size() > 0 {
405        std::alloc::dealloc(raw as *mut u8, layout);
406    }
407}
408
409/// A [`Waker`] that does nothing when waked.
410fn nop_waker() -> Waker {
411    const VTABLE: &RawWakerVTable = &RawWakerVTable::new(clone, nop, nop, nop);
412    unsafe fn clone(data: *const ()) -> RawWaker {
413        RawWaker::new(data, VTABLE)
414    }
415    unsafe fn nop(_: *const ()) {}
416    unsafe { Waker::from_raw(RawWaker::new(std::ptr::null(), VTABLE)) }
417}
418
419/// A helper interface used by the [`Fortify::new_async`] constructor.
420pub struct FortifyYielder<T>(*mut FortifyYielderData<T>);
421
422impl<T> FortifyYielder<T> {
423    /// Provides the [`Fortify`] value to this [`FortifyYielder`] and returns a [`Future`] that may
424    /// be awaited to suspend execution.
425    pub fn yield_(self, value: Lowered<T>) -> impl Future<Output = ()> + '_ {
426        unsafe {
427            let target = &mut *self.0;
428            target.value.write(value.value);
429            FortifyYielderFuture(&mut target.tracker)
430        }
431    }
432}
433
434struct FortifyYielderData<T> {
435    value: MaybeUninit<T>,
436    tracker: FortifyYielderTracker,
437}
438
439struct FortifyYielderTracker {
440    cx_ptr: *const (),
441    has_awaited: bool,
442}
443
444struct FortifyYielderFuture(*mut FortifyYielderTracker);
445
446impl Future for FortifyYielderFuture {
447    type Output = ();
448
449    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
450        unsafe {
451            // Verify the context to ensure that this future is being polled by `new_async` rather
452            // than by the user.
453            let tracker = &mut *self.as_ref().0;
454            if tracker.cx_ptr == (cx as *const Context as *const ()) {
455                // Inform `new_async` that the future has been awaited. This enables the value
456                // written to `FortifyYielderData` to be used.
457                tracker.has_awaited = true;
458            }
459        }
460        Poll::Pending
461    }
462}
463
464/// A helper macro for creating a `Fortify` using generator-like syntax. The macro takes a block of
465/// statements that ends with a `yield` of some expression. The block will be executed up to the
466/// `yield` statement, at which point the value of expression will be bundled with the suspended
467/// scope of the block and returned as a `Fortify`ied value. Local variables defined in the block
468/// may be accessed through references in the wrapped value.
469///
470/// # Example
471/// ```
472/// use fortify::*;
473/// let external = 1;
474/// let mut fortified: Fortify<(&i32, &i32)> = fortify! {
475///     let internal = 2;
476///     yield (&external, &internal);
477/// };
478/// let (external_ref, internal_ref) = *fortified.borrow();
479/// assert_eq!(*external_ref, 1);
480/// assert_eq!(*internal_ref, 2);
481/// ```
482#[macro_export]
483macro_rules! fortify {
484    (@INNER $y:ident , yield $res:expr ;) => {
485        $y.yield_(Lowered::new($res)).await
486    };
487    (@INNER $y:ident , $st:stmt ; $($t:tt)*) => {
488        { $st fortify!(@INNER $y , $($t)*) }
489    };
490    ($($t:tt)*) => {
491        $crate::Fortify::new_async(move |y| async move {
492            fortify!(@INNER y , $($t)*)
493        })
494    };
495}
496
497#[cfg(test)]
498mod tests;