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;