droppable_pin/_lib.rs
1//! [`droppable_pin!`]: `droppable_pin!`
2//! [`pin_drop!`]: `pin_drop!`
3//! [`pin_set!`]: `pin_set!`
4#![doc = include_str!("../README.md")]
5#![no_std]
6#![allow(unused_braces)]
7// Base image sourced from Disney's The Lion King, used under fair use.
8#![doc(html_logo_url = "\
9 https://github.com/danielhenrymantilla/droppable-pin.rs/blob/\
10 72bfcfec4e7499eed9fedbc79e8941fed722387e\
11 /assets/droppable_pin_logo.jpg?raw=true\
12")]
13
14/// Invoke this macro around a given `let [mut] var = pin!()` declaration to allow invoking
15/// [`pin_drop!`] and [`pin_set!`] on the given `var`, which have in turn been designed to avoid
16/// silly borrow-checking errors.
17///
18/// # Syntax usage
19///
20/// ```rust
21/// # use ::core::pin::pin;
22/// # use ::droppable_pin::droppable_pin;
23/// # async fn foo() {}
24/// # async fn bar() {}
25/// # /*
26/// droppable_pin! {
27/// let mut <varname> = pin!(<expr>);
28/// /* You may have multiple such declarations in the same macro invocation. */
29/// }
30/// # */
31///
32/// // For instance:
33/// droppable_pin! {
34/// let mut a = pin!(foo());
35/// let mut b = pin!(bar());
36/// }
37/// ```
38///
39/// # Motivation
40///
41/// <details open class="custom"><summary><span class="summary-box"><span>Click to hide</span></span></summary>
42///
43/// This is mainly useful when wanting to re-assign an `&mut`-borrowing `async fn` output (or,
44/// more generally, some `-> impl Trait` value (or, even more generally, some value with drop glue
45/// that makes use of that `&mut` borrow)) to some `pin!` value.
46///
47/// For instance, consider the following snippet:
48///
49/// ```rust, compile_fail
50/// async fn some_async_fn(_: &mut i32) {}
51///
52/// let mut borrowed = 42;
53/// let mut p = None;
54/// for _ in 0..2 {
55/// p = Some(some_async_fn(&mut borrowed));
56/// }
57/// ```
58///
59/// which errors with:
60///
61/// ```rust ,ignore
62/// # (); /*
63/// error[E0499]: cannot borrow `borrowed` as mutable more than once at a time
64/// --> src/_lib.rs:70:23
65/// |
66/// 8 | p = some_async_fn(&mut borrowed);
67/// | ^^^^^^^^^^^^^ `borrowed` was mutably borrowed here in the previous iteration of the loop
68/// 9 | }
69/// # */
70/// ```
71///
72/// And even if you set `p` to `None` before the assignment:
73///
74/// ```rust ,compile_fail
75/// async fn some_async_fn(_: &mut i32) {}
76///
77/// let mut borrowed = 42;
78/// let mut p;
79/// for _ in 0..2 {
80/// p = None;
81/// p = Some(some_async_fn(&mut borrowed));
82/// }
83/// ```
84///
85/// it will still fail, with:
86///
87/// ```rust ,ignore
88/// # (); /*
89/// error[E0499]: cannot borrow `borrowed` as mutable more than once at a time
90/// --> src/_lib.rs:94:28
91/// |
92/// 8 | p = None;
93/// | - first borrow might be used here, when `p` is dropped and runs the destructor for type `Option<impl Future<Output = ()>>`
94/// 9 | p = Some(some_async_fn(&mut borrowed));
95/// | ^^^^^^^^^^^^^ `borrowed` was mutably borrowed here in the previous iteration of the loop
96/// # */
97/// ```
98///
99/// - Notice how the error message already starts mentioning ``the destructor for type `Option<impl …>```.
100///
101/// The only solution, here, is to actually `drop`/move out of the `p` variable, so as to properly
102/// mark it as "empty"/exhausted to Rust (dropck, to be more precise), so that the borrow-checker
103/// give its green-light to this snippet:
104///
105/// ```rust
106/// async fn some_async_fn(_: &mut i32) {}
107///
108/// let mut borrowed = 42;
109/// let mut p = None;
110/// for _ in 0..2 {
111/// drop(p);
112/// p = Some(some_async_fn(&mut borrowed)); // ✅
113/// }
114/// ```
115///
116/// So far so good, but now consider that for this pattern to be genuinely useful, we will want to
117/// *actually use `p`* in the loop, and since it's owned from outside, we will probably want to be
118/// using it **by reference**, that is, behind (exclusive) pointer _indirection_!.
119///
120/// And in the context of `async fn`s, such indirection needs to be `Pin`-wrapped:
121///
122/// ```rust ,compile_fail
123/// async fn some_async_fn() {}
124///
125/// # async {
126/// let mut p = some_async_fn();
127/// // Error, needed either for `some_async_fn()` to be `Unpin`,
128/// // or for the reference to be a `Pin`-wrapped one.
129/// (&mut p).await;
130/// # };
131/// ```
132///
133/// The correct way to do this would be:
134///
135/// ```rust
136/// async fn some_async_fn() {}
137///
138/// # async {
139/// let mut p = ::core::pin::pin!(some_async_fn());
140/// p.as_mut().await; // ✅
141/// # };
142/// ```
143///
144/// But going back to our `loop {}`-dropck-borrow-checking-error situation, this runs into a problem:
145///
146/// ```rust ,compile_fail
147/// use ::core::pin::pin;
148///
149/// async fn some_async_fn(_: &mut i32) {}
150///
151/// let mut borrowed = 42;
152/// let mut p = pin!(None);
153/// for _ in 0..2 {
154/// drop(*p); // <- Err… how are we supposed to `drop()` the thing? It is what our `pin!`
155/// // points to, but the very safety and soundness of the design of `pin!` is for
156/// // us not to be able to mishandle it! 😕😕
157/// p.set(Some(some_async_fn(&mut borrowed)));
158/// }
159/// ```
160///
161/// Hence the problem.
162///
163/// This is where the [`droppable_pin!`] macro, alongside [`pin_drop!`] and [`pin_set!`], enter into
164/// play:
165///
166/// </details>
167///
168/// ## Example
169///
170/// ```rust
171/// use ::core::pin::pin;
172/// use ::droppable_pin::{droppable_pin, pin_drop, pin_set};
173///
174/// async fn some_async_fn(_: &mut i32) {}
175///
176/// let mut borrowed = 42;
177/// droppable_pin! { // 👈
178/// let mut p = pin!(None);
179/// }
180/// for _ in 0..2 {
181/// pin_drop!(p); // 👈
182/// pin_set!(p, Some(some_async_fn(&mut borrowed))); // ✅
183/// // 👆
184/// }
185/// ```
186///
187/// ### A more realistic example
188///
189/// ```rust
190/// use ::core::pin::pin;
191/// use ::droppable_pin::{droppable_pin, pin_drop, pin_set}; // 👈
192/// use ::futures_util::future::{Fuse, FusedFuture, FutureExt};
193///
194/// async fn foo() {}
195/// async fn bar(_borrowed: &mut i32) {}
196///
197/// # fn block_on(fut: impl Future<Output = ()>) {
198/// # fut.now_or_never().expect("there to be no suspensions")
199/// # }
200/// #
201/// # block_on(async {
202/// let mut borrowed = 42;
203/// droppable_pin! { // 👈
204/// let mut a = pin!(foo().fuse());
205/// let mut b = pin!(bar(&mut borrowed).fuse());
206/// }
207/// loop {
208/// ::futures_util::select! {
209/// () = a.as_mut() => {
210/// /* handle this case... */
211/// # if true { break; }
212///
213/// // Setup for next loop iteration:
214/// pin_set!(a, foo().fuse());
215/// // 👆
216/// // same as:
217/// a.set(foo().fuse());
218/// },
219/// () = b.as_mut() => {
220/// /* handle this case... */
221///
222/// // Setup for next loop iteration:
223/// // 1. Needed because of the `&mut borrowed` capture (see # Motivation).
224/// // 👇
225/// pin_drop!(b);
226/// pin_set!(b, bar(&mut borrowed).fuse());
227/// // 👆
228/// // 2. Cannot use `Pin::set()` here because of `pin_drop!()`.
229/// },
230/// }
231/// }
232/// # });
233/// ```
234///
235/// And rewritten to avoid code duplication (of the (re)initializations of `a` and `b`):
236///
237/// ```rust
238/// use ::core::pin::pin;
239/// use ::droppable_pin::{droppable_pin, pin_drop, pin_set}; // 👈
240/// use ::futures_util::future::{Fuse, FusedFuture, FutureExt};
241///
242/// async fn foo() {}
243/// async fn bar(_borrowed: &mut i32) {}
244///
245/// # fn block_on(fut: impl Future<Output = ()>) {
246/// # fut.now_or_never().expect("there to be no suspensions")
247/// # }
248/// #
249/// # block_on(async {
250/// let mut borrowed = 42;
251/// droppable_pin! { // 👈
252/// let mut a = pin!(Fuse::terminated());
253/// let mut b = pin!(Fuse::terminated());
254/// }
255/// loop {
256/// if a.is_terminated() {
257/// // 👇
258/// pin_set!(a, foo().fuse());
259/// // same as:
260/// a.set(foo().fuse());
261/// }
262/// if b.is_terminated() {
263/// // 1. Needed because of the `&mut borrowed` capture (see # Motivation).
264/// // 👇
265/// pin_drop!(b);
266/// pin_set!(b, bar(&mut borrowed).fuse());
267/// // 👆
268/// // 2. Cannot use `Pin::set()` here because of `pin_drop!()`.
269/// }
270/// ::futures_util::select! {
271/// () = a.as_mut() => {
272/// /* handle this case... */
273/// # if true { break; }
274/// },
275/// () = b.as_mut() => {
276/// /* handle this case... */
277/// },
278/// }
279/// }
280/// # });
281/// ```
282#[macro_export]
283macro_rules! droppable_pin {(
284 $(
285 let mut $var:ident $(: $T:ty)? =
286 $($(@ if $leading:tt)? ::)? $($pin_macro:ident)::+ !($value:expr $(,)?);
287 )+
288) => (
289 $(
290 // Note: safety-invariants-wise, `MaybeDangling<T>` and `T` are equivalent (they only
291 // differ in a subtle *validity* invariant aspect). Consider this to be an 100% transparent
292 // wrapper around `T`, whose only impact is for `Pin::new_unchecked()` to require a
293 // `DerefMut` call.
294 let mut hygiene_private_pinned_value = $crate::ඞ::maybe_dangling::MaybeDangling::new($value);
295
296 #[allow(unused_mut)]
297 let mut $var $(: $T)? = if true {
298 // SAFETY:
299 //
300 // `hygiene_private_pinned_value`, as indicated by its name, is hygiene-private
301 // and thus unable to be directly accessed by the user. So the user cannot misuse this,
302 // and we ourselves do not misuse it either (very similar SAFETY reasoning to that
303 // of stdlib `pin!`).
304 //
305 // Indeed:
306 //
307 // > we never move out of `hygiene_private_pinned_value` or otherwise invalidate its
308 // > backing storage without first calling its drop glue in-place!
309 //
310 // - The current `hygiene_private_pinned_value` is not `ManuallyDrop`-ped, so by the
311 // time it goes out of scope it shall be disposed of by the Rust scope machinery,
312 // which properly drops it in-place (c.f. stdlib `pin!`).
313 //
314 // - The only other (non-stdlib macro) usages we perform on
315 // `hygiene_private_pinned_value` are the following:
316 //
317 // - we may `pin_drop!` it (as defined by the following `…ඞpindrop_$var` macro).
318 //
319 // This drops it in-place (which invalidates the borrow held in `$var`, making
320 // the `Pin` no longer accessible), which abides by and puts an end to the `Pin`
321 // guarantee.
322 //
323 // For instance, as far as the `Pin` contract is concerned, we get to be able to
324 // "move" the value around again.
325 //
326 // Granted, as far as the _safety invariants_ of that type are concerned, we
327 // ought to do nothing with that now dropped value.
328 //
329 // Which is why we merely `forget()` it, the one API guaranteed not to run into
330 // any safety invariants.
331 //
332 // - we may `pin_set!` it (as defined by the following `…ඞpinset_$var` macro).)
333 //
334 // - if the value was set / non-empty / non-exhausted, this first drops the
335 // value in its place, before assigning the new value (much like the safe
336 // `Pin::set()` API does).
337 //
338 // - else, the value was empty/exhausted, and the `Pin` borrow,
339 // lifetime-invalidated (and the `Pin` contract, fulfilled, by previous
340 // invocation of its drop glue), so there is nothing to be careful about
341 // w.r.t. pinning in this case.
342 //
343 // Once set, by re-applying the very reasoning we are having here, we get to
344 // "refresh" the `Pin` borrow with a new `&mut hygiene_private_pinned_value`
345 // borrow, so as to give it a proper, re-usable, lifetime (since the "previous"
346 // one got invalidated upon drop/set).
347 unsafe {
348 $crate::ඞ::core::pin::Pin::new_unchecked(&mut *hygiene_private_pinned_value)
349 }
350 } else {
351 // Dead-code branch so as to enforce that the otherwise merely syntactical/decorative
352 // `pin!()` macro in the input do match the real `pin!` macro.
353 //
354 // But since we are re-implementing it ourselves, there is no point in actually using
355 // it, hence why this check happens in an `unreachable_code` branch.
356 #[allow(unreachable_code)] {
357 loop {}
358 $($(if $leading)? ::)? $($pin_macro)::+ ! { $value }
359 }
360 };
361
362 $crate::ඞ::paste! {
363 /// The exact shape of this name is not part of the public API!
364 #[allow(unused)]
365 macro_rules! [< missing_droppable_pin_around_var_declaration_ඞpindrop_ $var >] {() => (
366 // `drop($var)` (unnecessary, just here for nicer UX. Using 1-tuple for clippy.)
367 _ = ($var, );
368
369 $crate::ඞ::maybe_dangling::drop_in_place!(hygiene_private_pinned_value);
370 // This is why `MaybeDangling` was used. Not only does it offer *exactly* our
371 // desired binding-consuming `drop_in_place`-to-abide-by-`Pin` API, but it also does
372 // so:
373 // - guarding against unwind-safety (_i.e., what if said drop were to panic; here
374 // the process would be aborted);
375 // - preventing an aliasing validity invariant violation in case
376 // `hygiene_private_pinned_value` contained a `noalias` type such as `&mut`.
377 //
378 // Morally, and papering over those "details", what this `drop_in_place!()` macro
379 // does is otherwise just:
380
381 /*
382 // SAFETY: see safety comment around `let mut $var` declaration.
383 unsafe {
384 // 1. Drop it in-place so as to abide by the `Pin` contract.
385 (&raw mut hygiene_private_pinned_value).drop_in_place();
386 }
387 // 2. Tag the binding itself as empty/exhausted for dropck to be aware of it, but
388 // without double-dropping the value.
389 $crate::ඞ::core::mem::forget(hygiene_private_pinned_value);
390 */
391 )}
392
393 /// The exact shape of this name is not part of the public API!
394 #[allow(unused)]
395 macro_rules! [< missing_droppable_pin_around_var_declaration_ඞpinset_ $var >] {( $new_value:expr ) => (
396 hygiene_private_pinned_value = $crate::ඞ::maybe_dangling::MaybeDangling::new($new_value);
397 // SAFETY: see safety comment around `let mut $var` declaration.
398 $var = unsafe {
399 $crate::ඞ::core::pin::Pin::new_unchecked(&mut *hygiene_private_pinned_value)
400 };
401 )}
402
403 #[allow(unused_imports)]
404 use $crate::ඞ::diagnostics::declaration_properly_wrapped_in_the_droppable_pin_macro as [< ඞcanary_ $var >];
405 }
406 )+
407)}
408
409/// Drops, *in-place*, the `value: T` to which the given `$var: Pin<&mut T>` points to.
410///
411/// It does so in a manner of which drop-check will be aware of, avoiding a borrow-checking error
412/// which the more naive `$var.set(<dummy>)` would run into.
413///
414/// Note that this API is only available for `$var: Pin<&mut _>` bindings which stem from
415/// a [`droppable_pin!`] invocation.
416#[macro_export]
417macro_rules! pin_drop {( $var:ident $(,)? ) => (
418 $crate::ඞ::check_var_stems_from_droppable_pin!($var);
419 $crate::ඞ::paste! {
420 [< missing_droppable_pin_around_var_declaration_ඞpindrop_ $var >]!();
421 }
422)}
423
424
425/// Same as <code>[Pin::set](&mut $var, $value)</code>, but usable even after [`pin_drop!`] has been
426/// invoked on the given `$var`.
427///
428/// Note that this API is only available for `$var: Pin<&mut _>` bindings which stem from
429/// a [`droppable_pin!`] invocation.
430///
431/// [Pin::set]: [`::core::pin::Pin::set()`]
432#[macro_export]
433macro_rules! pin_set {( $var:ident, $value:expr $(,)? ) => (
434 $crate::ඞ::check_var_stems_from_droppable_pin!($var);
435 $crate::ඞ::paste! {
436 [< missing_droppable_pin_around_var_declaration_ඞpinset_ $var >]!( $value );
437 }
438)}
439
440// macro internals
441#[doc(hidden)] /** Not part of the public API */ pub
442mod ඞ {
443 pub use ::core; // or `std`
444 pub use ::maybe_dangling;
445 pub use ::paste::paste;
446 #[doc(inline)]
447 pub use crate::ඞcheck_var_stems_from_droppable_pin as check_var_stems_from_droppable_pin;
448
449 pub mod diagnostics {
450 #![allow(nonstandard_style)]
451
452 pub const FALLBACK: the_given_var = the_given_var {};
453 pub struct the_given_var {}
454 pub struct declaration_properly_wrapped_in_the_droppable_pin_macro;
455
456 #[diagnostic::on_unimplemented(
457 message = "\
458 missing `droppable_pin! {{}}` macro invocation wrapping the `let var = pin!(…)` \
459 declaration of the given `var`\
460 ",
461 label = "\
462 wrap the `let var = pin!(…)` declaration of this `var` in a `droppable_pin! {{}}` \
463 macro invocation.
464Like this:
465
466droppable_pin! {{
467 let mut var = pin!(...);
468}}\
469 ",
470 note = "\
471 remember to wrap the `let var = pin!(…)` declaration of this `var` in a \
472 `droppable_pin! {{}}` macro invocation. Like so:
473
474droppable_pin! {{
475 let mut var = pin!(...);
476}}\
477 ",
478 note = "\
479 it is important that the given `var` not have been renamed \
480 (or re-assigned to differently-named binding)\
481 "
482 )]
483 pub trait declaration_of_the_variable_has_been_declaration_properly_wrapped_in_the_droppable_pin_macro {}
484
485 impl declaration_of_the_variable_has_been_declaration_properly_wrapped_in_the_droppable_pin_macro for declaration_properly_wrapped_in_the_droppable_pin_macro {}
486 pub fn check_var_stems_from_droppable_pin(_: impl declaration_of_the_variable_has_been_declaration_properly_wrapped_in_the_droppable_pin_macro) {}
487 }
488}
489
490/// Not part of the public API.
491///
492/// Checks that the given `$var` do correspond to a [`droppable_pin!`] declaration.
493#[macro_export]
494#[doc(hidden)]
495macro_rules! ඞcheck_var_stems_from_droppable_pin {( $var:ident $(,)? ) => ({
496 if false {
497 #[allow(warnings)] {
498 // ensure we are in dead-code in case `$var` has been `drop!`ped already.
499 loop {}
500 // 1. Basic, sanity type-check.
501 let _: $crate::ඞ::core::pin::Pin<&mut _> = $var;
502
503 // 2. (Ab)use `#[diagnostic::on_unimplemented()]` functionality and name shadowing
504 // to observe when the given variable does not have the associated names in scope,
505 // and then produce nicer-reading diagnostics suggesting the appropriate fix.
506 $crate::ඞ::paste!({
507 // This makes it so `[< ඞcanary_ $var >]` is in the current scope, at least in the
508 // *type* namespace (so that referring to it not fail, but also not shadow the
509 // genuine `[< ඞcanary_ $var >]` in the *value* namespace).
510 use $crate::ඞ::diagnostics::the_given_var as [< ඞcanary_ $var >];
511 // Make sure that `$var` be in the current scope (in any applicable
512 // namespace), so the following glob-import be of lesser priority and thus unable
513 // to shadow anything.
514 use [< ඞcanary_ $var >] as $var;
515 // Now glob-import with lower/fallback priority `$var` from any namespace which may
516 // currently be missing:
517 // - type namespace: always `the_given_var`.
518 // - value namespace: when properly-annotated, previous `use` brought it into
519 // scope, and is of type `declaration_properly_wrapped_in_the_droppable_pin_macro`.
520 // Otherwise, it brings `FALLBACK`, of type `the_given_var`.
521 use helper::*;
522 mod helper {
523 pub(super) use $crate::ඞ::diagnostics::FALLBACK as $var;
524 }
525 // Perform a trait implementation assertion, knowing that `the_given_var` does not
526 // implement it, whereas `declaration_properly_wrapped_in_the_droppable_pin_macro`
527 // does. The trait is aptly named
528 // declaration_of_the_variable_has_been_declaration_properly_wrapped_in_the_droppable_pin_macro
529 // and features extra, human-readable, `#[diagnostic::on_unimplemented()]` diagnostics.
530 $crate::ඞ::diagnostics::check_var_stems_from_droppable_pin($var);
531 });
532 }
533 }
534})}
535
536#[doc = include_str!("compile_fail_tests.md")]
537mod _compile_fail_tests {}