fortify 0.4.1

A simple and convenient way to bundle owned data with a borrowing type
Documentation
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
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
#![warn(missing_docs)]
//! This crate provides the [`Fortify`] wrapper type. When used with a borrowing type (i.e. a type
//! with a lifetime parameter) it allows values of that type to reference arbitrary data owned by
//! the `Fortify` itself.
//!
//! # Example
//! ```
//! use fortify::*;
//!
//! // Define a borrowing type. The `Lower` trait specifies that it is covariant in its first
//! // lifetime parameter.
//! #[derive(Lower)]
//! struct Example<'a> {
//!    a: &'a i32,
//!    b: &'a mut i32,
//! }
//!
//! // Construct a fortified value that makes an "external" reference to `a` and an "internal"
//! // reference to `b`, which is owned by the Fortify.
//! let a = 1;
//! let mut example: Fortify<Example> = fortify! {
//!     let mut b = 1;
//!     b += 1;
//!     yield Example {
//!         a: &a,
//!         b: &mut b
//!     };
//! };
//!
//! // Use `with_mut` for general mutable access to the wrapped value. Note that the reference
//! // to `b` is still valid even though `b` is not in scope in this block.
//! example.with_mut(|example| {
//!     assert_eq!(*example.a, 1);
//!     assert_eq!(*example.b, 2);
//!     *example.b += 1;
//!     assert_eq!(*example.b, 3);
//! });
//! ```
extern crate self as fortify;
mod lower;

pub use fortify_derive::*;
pub use lower::*;
use std::future::Future;
use std::mem::{transmute_copy, ManuallyDrop, MaybeUninit};
use std::pin::Pin;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};

/// Wraps a value of type `T` and allows it to reference arbitrary supplementary data owned by the
/// [`Fortify`]. This can be used to effectively convert a borrowing type into an owning type.
///
/// # Example
/// ```
/// use fortify::*;
/// let example: Fortify<&'static str> = fortify! {
///     let mut str = String::new();
///     str.push_str("Foo");
///     str.push_str("Bar");
///     yield str.as_str();
/// };
/// example.with_ref(|s| assert_eq!(s, &"FooBar"));
/// assert_eq!(example.borrow(), &"FooBar");
/// ```
pub struct Fortify<T> {
    value: ManuallyDrop<T>,
    data_raw: *mut (),
    data_drop_fn: unsafe fn(*mut ()),
}

impl<T> Fortify<T> {
    /// Directly constructs a [`Fortify`] wrapper over the given value.
    pub fn new(value: T) -> Self {
        Self {
            value: ManuallyDrop::new(value),
            data_raw: std::ptr::null_mut(),
            data_drop_fn: drop_nop,
        }
    }
}

impl<'a, T: Refers<'a>> Fortify<T> {
    /// Creates a [`Fortify`] by explicitly providing its owned data and constructing its value
    /// from that using a closure. Note that for technical reasons, the constructed value must be
    /// wrapped in a [`Lowered`] wrapper.
    ///
    /// # Example
    /// ```
    /// use fortify::{Fortify, Lowered};
    /// let mut str = String::new();
    /// str.push_str("Hello");
    /// let fortified: Fortify<&str> = Fortify::new_dep(str, |s| Lowered::new(s.as_str()));
    /// assert_eq!(fortified.borrow(), &"Hello");
    /// ```
    pub fn new_dep<O: 'a, C>(owned: O, cons: C) -> Self
    where
        C: for<'b> FnOnce(&'b mut O) -> Lowered<'b, T>,
    {
        Self::new_box_dep(Box::new(owned), cons)
    }

    /// Creates a [`Fortify`] by explicitly providing its owned data (as a [`Box`]) and
    /// constructing its value from that using a closure. Note that for technical reasons, the
    /// constructed value must be wrapped in a [`Lowered`] wrapper.
    pub fn new_box_dep<O: 'a, C>(owned: Box<O>, cons: C) -> Self
    where
        C: for<'b> FnOnce(&'b mut O) -> Lowered<'b, T>,
    {
        let owned = Box::into_raw(owned);
        let value = cons(unsafe { &mut *owned });
        Self {
            value: ManuallyDrop::new(value.value),
            data_raw: owned as *mut (),
            data_drop_fn: drop_box_from_raw::<O>,
        }
    }

    /// Creates a [`Fortify`] by using a [`Future`] to construct the `Fortify`'s value. As soon
    /// as the `Future` "yields" a value, it will be suspended and become the supplementary data
    /// for the `Fortify`. This allows the inner value to reference locals defined by the `Future`.
    ///
    /// The `Future` must await on [`FortifyYielder::yield_`] and nothing else. Code following the
    /// await may or may not be executed.
    ///
    /// This is a hacky way of taking advantage of rust's code generation for async in order to
    /// suspend an executing block of code. In the future, when 'generators' is stabilized, this
    /// would be unnecessary. Therefore, it is recommended to use the [`fortify!`] macro instead.
    ///
    /// # Example
    /// ```
    /// use fortify::{Fortify, Lowered};
    /// let external = 1;
    /// let mut fortified: Fortify<(&i32, &i32)> = Fortify::new_async(|y| async {
    ///     let internal = 2;
    ///     y.yield_(Lowered::new((&external, &internal))).await;
    /// });
    /// let (external_ref, internal_ref) = *fortified.borrow();
    /// assert_eq!(*external_ref, 1);
    /// assert_eq!(*internal_ref, 2);
    /// ```
    pub fn new_async<C, F>(cons: C) -> Self
    where
        C: 'a + FnOnce(FortifyYielder<T>) -> F,
        F: 'a + Future<Output = ()>,
    {
        let waker = nop_waker();
        let mut cx = Context::from_waker(&waker);
        let mut data = FortifyYielderData {
            value: MaybeUninit::uninit(),
            tracker: FortifyYielderTracker {
                cx_ptr: &cx as *const Context as *const (),
                has_awaited: false,
            },
        };
        let future = Box::into_raw(Box::new(cons(FortifyYielder(&mut data))));
        match Future::poll(unsafe { Pin::new_unchecked(&mut *future) }, &mut cx) {
            Poll::Ready(_) => {
                unsafe { drop_box_from_raw::<F>(future as *mut ()) };
                panic!("Future must await on FortifyYielder::yield_")
            }
            Poll::Pending => {
                if data.tracker.has_awaited {
                    Self {
                        value: ManuallyDrop::new(unsafe {
                            transmute_copy(data.value.assume_init_ref())
                        }),
                        data_raw: future as *mut (),
                        data_drop_fn: drop_box_from_raw::<F>,
                    }
                } else {
                    unsafe { drop_box_from_raw::<F>(future as *mut ()) };
                    panic!("Future may only await on FortifyYielder::yield_")
                }
            }
        }
    }
}

impl<'a, T: Lower<'a, Target = T>> Fortify<&'a T> {
    /// Creates a [`Fortify`] by taking ownership of a [`Box`] and wrapping a reference to
    /// the value inside it.
    ///
    /// # Example
    /// ```
    /// use fortify::Fortify;
    /// let value = Box::new(123);
    /// let mut fortified: Fortify<&i32> = Fortify::new_box_ref(value);
    /// assert_eq!(**fortified.borrow(), 123);
    /// assert_eq!(fortified.with_inner(|x| *x), 123);
    /// ```
    pub fn new_box_ref(value: Box<T>) -> Self {
        Self::new_box_dep(value, |inner| Lowered::new(&*inner))
    }
}

impl<'a, T: 'a> Fortify<&'a mut T> {
    /// Creates a [`Fortify`] by taking ownership of a [`Box`] and wrapping a mutable reference to
    /// the value inside it.
    ///
    /// # Example
    /// ```
    /// use fortify::Fortify;
    /// let value = Box::new(123);
    /// let mut fortified: Fortify<&mut i32> = Fortify::new_box_mut(value);
    /// fortified.with_mut(|v| **v *= 2);
    /// assert_eq!(**fortified.borrow(), 246);
    /// ```
    pub fn new_box_mut(value: Box<T>) -> Self {
        Self::new_box_dep(value, |inner| Lowered::new(inner))
    }
}

impl<'a, T: Lower<'a>> Fortify<T> {
    /// Immutably borrows the value inside a [`Fortify`]. For more general access to the wrapped
    /// value, see [`Fortify::with_ref`] and [`Fortify::with_mut`].
    #[allow(clippy::should_implement_trait)]
    // We would like to implement `std::borrow::Borrow`, but it's not possible to specify the
    // lifetime correctly.
    pub fn borrow(&'a self) -> &'a <T as Lower<'a>>::Target {
        let value = &*self.value;
        unsafe { transmute_copy(&value) }
    }
}

impl<T: for<'a> Lower<'a>> Fortify<T> {
    /// Executes a closure using an immutable reference to the value stored inside this [`Fortify`].
    ///
    /// Calls to `with_ref` can typically be replaced with and simplified using `borrow`. This
    /// method is retained for consistency with `with_mut` and possible support for non-covariant
    /// types (which can't use `borrow`) in the future.
    pub fn with_ref<'a, F, R>(&'a self, f: F) -> R
    where
        F: for<'b> FnOnce(&'a <T as Lower<'b>>::Target) -> R,
    {
        let value = &*self.value;
        f(unsafe { transmute_copy(&value) })
    }

    /// Executes a closure using a mutable reference to the value stored inside this [`Fortify`].
    pub fn with_mut<'a, F, R>(&'a mut self, f: F) -> R
    where
        F: for<'b> FnOnce(&'a mut <T as Lower<'b>>::Target) -> R,
    {
        let value = &mut *self.value;
        f(unsafe { transmute_copy(&value) })
    }

    /// Executes a closure with the value stored inside this [`Fortify`], effectively destructing
    /// the wrapper.
    pub fn with_inner<F, R>(self, f: F) -> R
    where
        for<'a> <T as Lower<'a>>::Target: Sized,
        F: for<'a> FnOnce(<T as Lower<'a>>::Target) -> R,
    {
        self.split(|inner| (Lowered::new(()), f(Lowered::unwrap(inner))))
            .1
    }
}

impl<'a, T: 'a> Fortify<T> {
    /// Maps and splits this [`Fortify`] wrapper into a component that references its owned
    /// data, and a component that doesn't. This is a generalization of both [`Fortify::map`] and
    /// [`Fortify::with_inner`].
    ///
    /// # Example
    /// ```
    /// use fortify::*;
    /// let fortified: Fortify<(&i32, i32)> = fortify! {
    ///     let x = 12;
    ///     yield (&x, 15);
    /// };
    /// let (x, y) = fortified.split(|inner| (Lowered::new(inner.0), inner.1));
    /// assert_eq!(**x.borrow(), 12);
    /// assert_eq!(y, 15);
    /// ```
    pub fn split<F, N, R>(mut self, f: F) -> (Fortify<N>, R)
    where
        N: Refers<'a>,
        F: for<'b> FnOnce(Lowered<'b, T>) -> (Lowered<'b, N>, R),
    {
        let value = unsafe { ManuallyDrop::take(&mut self.value) };
        let data_raw = self.data_raw;
        let data_drop_fn = self.data_drop_fn;
        std::mem::forget(self);
        let (value, res) = f(Lowered {
            value,
            marker: std::marker::PhantomData,
        });
        (
            Fortify {
                value: ManuallyDrop::new(value.value),
                data_raw,
                data_drop_fn,
            },
            res,
        )
    }

    /// Constructs a new [`Fortify`] wrapper by applying a mapping function to the value stored
    /// in this wrapper. The resulting [`Fortify`] will carry the exact same owned data as this
    /// does.
    pub fn map<F, N>(self, f: F) -> Fortify<N>
    where
        N: Refers<'a>,
        F: for<'b> FnOnce(Lowered<'b, T>) -> Lowered<'b, N>,
    {
        self.split(|inner| (f(inner), ())).0
    }
}

/// Indicates that, if this type has a non-trivial implementation of [`Lower`], it references
/// the lifetime `'a`. Thus, the bound `T: Refers<'a>` can be thought of as the inverse of `T: 'a`.
///
/// This is used by various [`Fortify`]-constructing functions to ensure that the resulting
/// wrapper does not outlive the external references it contains. This will be automatically
/// implemented for any type that correctly implements [`Lower`].
pub trait Refers<'a> {}

impl<'a, T: Lower<'a, Target = T>> Refers<'a> for T {}

impl<T> From<T> for Fortify<T> {
    fn from(value: T) -> Self {
        Fortify::new(value)
    }
}

impl<'a, T: Lower<'a, Target = T>> From<Box<T>> for Fortify<&'a T> {
    fn from(value: Box<T>) -> Self {
        Fortify::new_box_ref(value)
    }
}

impl<'a, T> From<Box<T>> for Fortify<&'a mut T> {
    fn from(value: Box<T>) -> Self {
        Fortify::new_box_mut(value)
    }
}

impl<T: Default> Default for Fortify<T> {
    fn default() -> Self {
        Fortify::new(T::default())
    }
}

impl<T> std::fmt::Debug for Fortify<T>
where
    for<'a> T: Lower<'a>,
    for<'a> <T as Lower<'a>>::Target: std::fmt::Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.borrow().fmt(f)
    }
}

impl<T> std::fmt::Display for Fortify<T>
where
    for<'a> T: Lower<'a>,
    for<'a> <T as Lower<'a>>::Target: std::fmt::Display,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.borrow().fmt(f)
    }
}

unsafe impl<'a, T: Lower<'a>> Lower<'a> for Fortify<T>
where
    T::Target: Sized,
{
    type Target = Fortify<T::Target>;
}

impl<T: Iterator> Iterator for Fortify<T>
where
    for<'a> T: Lower<'a>,
    for<'a> <T as Lower<'a>>::Target: Iterator<Item = T::Item>,
{
    type Item = T::Item;
    fn next(&mut self) -> Option<Self::Item> {
        self.with_mut(|inner| inner.next())
    }
}

impl<T> Drop for Fortify<T> {
    fn drop(&mut self) {
        unsafe {
            // Value must be dropped before data
            ManuallyDrop::drop(&mut self.value);
            (self.data_drop_fn)(self.data_raw);
        }
    }
}

/// Does nothing.
unsafe fn drop_nop(_: *mut ()) {
    // Nothing to do here
}

/// Constructs a box from its raw pointer and then drops it.
unsafe fn drop_box_from_raw<T>(raw: *mut ()) {
    // NOTE: It may seem easier to convert to a box and drop it here, but that may trigger UB if
    // the box contains self-references (which is common with futures). Instead, we'll use the
    // destruction pattern from https://doc.rust-lang.org/std/boxed/struct.Box.html#method.into_raw
    std::ptr::drop_in_place(raw as *mut T);
    let layout = std::alloc::Layout::new::<T>();
    if layout.size() > 0 {
        std::alloc::dealloc(raw as *mut u8, layout);
    }
}

/// A [`Waker`] that does nothing when waked.
fn nop_waker() -> Waker {
    const VTABLE: &RawWakerVTable = &RawWakerVTable::new(clone, nop, nop, nop);
    unsafe fn clone(data: *const ()) -> RawWaker {
        RawWaker::new(data, VTABLE)
    }
    unsafe fn nop(_: *const ()) {}
    unsafe { Waker::from_raw(RawWaker::new(std::ptr::null(), VTABLE)) }
}

/// A helper interface used by the [`Fortify::new_async`] constructor.
pub struct FortifyYielder<T>(*mut FortifyYielderData<T>);

impl<T> FortifyYielder<T> {
    /// Provides the [`Fortify`] value to this [`FortifyYielder`] and returns a [`Future`] that may
    /// be awaited to suspend execution.
    pub fn yield_(self, value: Lowered<T>) -> impl Future<Output = ()> + '_ {
        unsafe {
            let target = &mut *self.0;
            target.value.write(value.value);
            FortifyYielderFuture(&mut target.tracker)
        }
    }
}

struct FortifyYielderData<T> {
    value: MaybeUninit<T>,
    tracker: FortifyYielderTracker,
}

struct FortifyYielderTracker {
    cx_ptr: *const (),
    has_awaited: bool,
}

struct FortifyYielderFuture(*mut FortifyYielderTracker);

impl Future for FortifyYielderFuture {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        unsafe {
            // Verify the context to ensure that this future is being polled by `new_async` rather
            // than by the user.
            let tracker = &mut *self.as_ref().0;
            if tracker.cx_ptr == (cx as *const Context as *const ()) {
                // Inform `new_async` that the future has been awaited. This enables the value
                // written to `FortifyYielderData` to be used.
                tracker.has_awaited = true;
            }
        }
        Poll::Pending
    }
}

/// A helper macro for creating a `Fortify` using generator-like syntax. The macro takes a block of
/// statements that ends with a `yield` of some expression. The block will be executed up to the
/// `yield` statement, at which point the value of expression will be bundled with the suspended
/// scope of the block and returned as a `Fortify`ied value. Local variables defined in the block
/// may be accessed through references in the wrapped value.
///
/// # Example
/// ```
/// use fortify::*;
/// let external = 1;
/// let mut fortified: Fortify<(&i32, &i32)> = fortify! {
///     let internal = 2;
///     yield (&external, &internal);
/// };
/// let (external_ref, internal_ref) = *fortified.borrow();
/// assert_eq!(*external_ref, 1);
/// assert_eq!(*internal_ref, 2);
/// ```
#[macro_export]
macro_rules! fortify {
    (@INNER $y:ident , yield $res:expr ;) => {
        $y.yield_(Lowered::new($res)).await
    };
    (@INNER $y:ident , $st:stmt ; $($t:tt)*) => {
        { $st fortify!(@INNER $y , $($t)*) }
    };
    ($($t:tt)*) => {
        $crate::Fortify::new_async(move |y| async move {
            fortify!(@INNER y , $($t)*)
        })
    };
}

#[cfg(test)]
mod tests;