pub macro pin($value:expr $(,)?) {
...
}
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 { /* … */ }));
RunManually 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,
}
}
}
RunWith Generator
s
#![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(()) => {},
}
}
RunRemarks
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
RunError 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.
If the (type
T
of the) given value does not implementUnpin
, then this effectively pins thevalue
in memory, where it will be unable to be moved. Otherwise,Pin<&mut T>
behaves like&mut T
, and operations such asmem::replace()
will allow extracting that value, and therefore, moving it. See theUnpin
section of thepin
module for more info. ↩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 anasync fn
or block —more generally, the body of a generator— any locals crossing an.await
point —ayield
point— end up being part of the state captured by theFuture
—by theGenerator
—, and thus will be stored wherever that one is. ↩