Macro std::pin::pin

source ·
pub macro pin($value:expr $(,)?) {
    ...
}
🔬This is a nightly-only experimental API. (pin_macro #93178)
Expand description

Constructs a Pin<&mut T>, by pinning1 a value: T locally2.

Unlike Box::pin, this does not involve a heap allocation.

Examples

Basic usage

#![feature(pin_macro)]
use core::pin::{pin, Pin};

fn stuff(foo: Pin<&mut Foo>) {
    // …
}

let pinned_foo = pin!(Foo { /* … */ });
stuff(pinned_foo);
// or, directly:
stuff(pin!(Foo { /* … */ }));
Run

Manually polling a Future (without Unpin bounds)

#![feature(pin_macro)]
use std::{
    future::Future,
    pin::pin,
    task::{Context, Poll},
    thread,
};

/// Runs a future to completion.
fn block_on<Fut: Future>(fut: Fut) -> Fut::Output {
    let waker_that_unparks_thread = // …
    let mut cx = Context::from_waker(&waker_that_unparks_thread);
    // Pin the future so it can be polled.
    let mut pinned_fut = pin!(fut);
    loop {
        match pinned_fut.as_mut().poll(&mut cx) {
            Poll::Pending => thread::park(),
            Poll::Ready(res) => return res,
        }
    }
}
Run

With Generators

#![feature(generators, generator_trait, pin_macro)]
use core::{
    ops::{Generator, GeneratorState},
    pin::pin,
};

fn generator_fn() -> impl Generator<Yield = usize, Return = ()> /* not Unpin */ {
 // Allow generator to be self-referential (not `Unpin`)
 // vvvvvv        so that locals can cross yield points.
    static || {
        let foo = String::from("foo");
        let foo_ref = &foo; // ------+
        yield 0;                  // | <- crosses yield point!
        println!("{foo_ref}"); // <--+
        yield foo.len();
    }
}

fn main() {
    let mut generator = pin!(generator_fn());
    match generator.as_mut().resume(()) {
        GeneratorState::Yielded(0) => {},
        _ => unreachable!(),
    }
    match generator.as_mut().resume(()) {
        GeneratorState::Yielded(3) => {},
        _ => unreachable!(),
    }
    match generator.resume(()) {
        GeneratorState::Yielded(_) => unreachable!(),
        GeneratorState::Complete(()) => {},
    }
}
Run

Remarks

Precisely because a value is pinned to local storage, the resulting Pin<&mut T> reference ends up borrowing a local tied to that block: it can’t escape it.

The following, for instance, fails to compile:

#![feature(pin_macro)]
use core::pin::{pin, Pin};

let x: Pin<&mut Foo> = {
    let x: Pin<&mut Foo> = pin!(Foo { /* … */ });
    x
}; // <- Foo is dropped
stuff(x); // Error: use of dropped value
Run
Error message
error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:9:28
   |
8  | let x: Pin<&mut Foo> = {
   |     - borrow later stored here
9  |     let x: Pin<&mut Foo> = pin!(Foo { /* … */ });
   |                            ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
10 |     x
11 | }; // <- Foo is dropped
   | - temporary value is freed at the end of this statement
   |
   = note: consider using a `let` binding to create a longer lived value

This makes pin! unsuitable to pin values when intending to return them. Instead, the value is expected to be passed around unpinned until the point where it is to be consumed, where it is then useful and even sensible to pin the value locally using pin!.

If you really need to return a pinned value, consider using Box::pin instead.

On the other hand, pinning to the stack2 using pin! is likely to be cheaper than pinning into a fresh heap allocation using Box::pin. Moreover, by virtue of not even needing an allocator, pin! is the main non-unsafe #![no_std]-compatible Pin constructor.


  1. If the (type T of the) given value does not implement Unpin, then this effectively pins the value in memory, where it will be unable to be moved. Otherwise, Pin<&mut T> behaves like &mut T, and operations such as mem::replace() will allow extracting that value, and therefore, moving it. See the Unpin section of the pin module for more info. 

  2. This is usually dubbed “stack”-pinning. And whilst local values are almost always located in the stack (e.g., when within the body of a non-async function), the truth is that inside the body of an async fn or block —more generally, the body of a generator— any locals crossing an .await point —a yield point— end up being part of the state captured by the Future —by the Generator—, and thus will be stored wherever that one is.