| name | rust-pin |
| description | Pin and self-referential types expert covering Pin, Unpin, Future, async state machines, pinning projection, and memory stability guarantees. |
| metadata | {"triggers":["Pin","Unpin","self-referential","Future","async","Generator","pinning","memory stability"]} |
When Pin is Needed
1. async/await Futures
use std::pin::Pin;
use std::task::{Context, Poll};
use std::future::Future;
struct MyFuture {
state: State,
}
impl Future for MyFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
Poll::Ready(())
}
}
2. Self-Referential Structures
use std::pin::Pin;
struct Node {
value: i32,
next: Option<Pin<Box<Node>>>,
}
Solution Patterns
Pattern 1: Pinning on Heap
use std::pin::Pin;
let future = async {
};
let pinned: Pin<Box<dyn Future<Output = ()>>> = Box::pin(future);
Pattern 2: Pinning with Pin::new_unchecked
use std::pin::Pin;
struct SelfReferential {
data: String,
ptr: *const String,
}
impl SelfReferential {
fn new(data: String) -> Pin<Box<Self>> {
let mut boxed = Box::new(SelfReferential {
data,
ptr: std::ptr::null(),
});
let ptr = &boxed.data as *const String;
boxed.ptr = ptr;
unsafe { Pin::new_unchecked(boxed) }
}
fn data(&self) -> &str {
unsafe { &*self.ptr }
}
}
Pattern 3: Pin Projection
use std::pin::Pin;
struct Wrapper<T> {
inner: T,
extra: String,
}
impl<T: Unpin> Wrapper<T> {
fn project(self: Pin<&mut Self>) -> Pin<&mut T> {
Pin::new(&mut self.get_mut().inner)
}
}
impl<T> Wrapper<T> {
fn project_unchecked(self: Pin<&mut Self>) -> Pin<&mut T> {
unsafe {
Pin::new_unchecked(&mut self.get_unchecked_mut().inner)
}
}
}
Pattern 4: Pinning in Async Context
use std::pin::Pin;
use futures::Future;
async fn process_data() {
let mut state = String::new();
let state_ref = &mut state;
some_async_operation().await;
state_ref.push_str("data");
}
Pin Types
| Type | Use Case | Example |
|---|
Pin<&T> | Borrowed, immutable | Pin<&Foo> |
Pin<&mut T> | Borrowed, mutable | Pin<&mut Foo> |
Pin<Box<T>> | Owned on heap | Pin<Box<Foo>> |
Pin<Arc<T>> | Shared ownership | Pin<Arc<Foo>> |
Unpin Marker Trait
struct MyType {
data: Vec<u8>,
}
use std::marker::PhantomPinned;
struct NotUnpin {
data: String,
_pin: PhantomPinned,
}
Workflow
Step 1: Determine if Pin Needed
Need Pin when:
โ async/await (Future trait)
โ Self-referential struct
โ Implementing custom Future
โ Working with generators
Don't need Pin when:
โ Synchronous code
โ No self-references
โ Stack-allocated temporaries
โ Type is Unpin
Step 2: Choose Pinning Strategy
Heap pinning:
โ Box::pin(value)
โ Safe, most common
Stack pinning:
โ pin!(value) // macro in std
โ More complex, zero allocation
Unsafe pinning:
โ Pin::new_unchecked()
โ Require SAFETY comments
Step 3: Handle Projections
Projecting to field:
โ If T: Unpin โ Safe with Pin::new
โ If !Unpin โ Unsafe, need Pin::new_unchecked
โ Use pin-project crate for safety
Common Use Cases
| Scenario | Need Pin? |
|---|
async {} block | โ
Yes (Future) |
Box<dyn Future> | โ
Yes |
| Self-referential struct | โ
Yes |
| Regular Vec/HashMap | โ No |
| Stack variables | โ No |
| No self-references | โ No |
Review Checklist
When working with Pin:
Verification Commands
cargo expand
cargo expand --lib my_async_fn
cargo +nightly miri test
Common Pitfalls
1. Forgetting to Pin Future
Symptom: Compilation error about poll signature
fn poll_future(mut future: impl Future) {
future.poll();
}
fn poll_future(mut future: Pin<&mut impl Future>) {
future.as_mut().poll(cx);
}
2. Moving Pinned Value
Symptom: Undefined behavior
let pinned = Box::pin(value);
let moved = *pinned;
let pinned = Box::pin(value);
let pinned_ref: Pin<&mut Value> = pinned.as_mut();
3. Incorrect Projection
Symptom: Unsoundness in self-referential types
impl<T> Wrapper<T> {
fn bad_project(self: Pin<&mut Self>) -> &mut T {
&mut self.get_mut().inner
}
}
impl<T: Unpin> Wrapper<T> {
fn safe_project(self: Pin<&mut Self>) -> Pin<&mut T> {
Pin::new(&mut self.get_mut().inner)
}
}
Related Skills
- rust-async - Async/await and Future trait
- rust-unsafe - Unsafe code for Pin::new_unchecked
- rust-ownership - Lifetime and borrowing
- rust-type-driven - PhantomPinned and marker types
- rust-performance - Zero-cost abstractions with Pin
Localized Reference
- Chinese version: SKILL_ZH.md - ๅฎๆดไธญๆ็ๆฌ๏ผๅ
ๅซๆๆๅ
ๅฎน