In this lesson, you will learn how to design safe APIs that guarantee a type remains stationary in memory, even when the rest of the program might try to move it.
The Problem of Movement
In Rust, most types are "movable" by default—meaning mem::replace or simple assignment can copy their bytes to a new location. However, self-referential types (like those used in async futures) store pointers to their own internal fields. If you move the struct, those internal pointers become dangling, leading to undefined behavior.
This is where Pin<P> comes in. Wrapping a pointer in Pin prevents the data it points to from being moved.
The Unpin Trait
Most types in Rust are Unpin. This marker trait simply means "it is safe to move this type even if it is pinned." Almost everything (like i32 or Vec) implements Unpin automatically.
When you want to prevent movement, you must work with types that do not implement Unpin. If a type is !Unpin, Pin creates a guarantee: the data is "pinned" to its current memory address until it is dropped.
Designing a Safe API
To design an API that forces stability, you don't usually need to write unsafe code if you leverage Pin. Consider a scenario where you are building a data structure that tracks its own memory address:
use std::pin::Pin;
use std::marker::PhantomPinned;
struct SelfReferential {
data: String,
// Using PhantomPinned makes the struct !Unpin
_marker: PhantomPinned,
}
impl SelfReferential {
fn new(val: &str) -> Self {
Self { data: val.to_string(), _marker: PhantomPinned }
}
}
By adding PhantomPinned, you tell the compiler: "this struct is not safe to move." Because the compiler now enforces !Unpin, any attempt to move the struct out of a Pin<Box<SelfReferential>> will result in a compilation error. Your API users are now physically prevented from breaking memory safety, and you have successfully constrained the "movement" capabilities of the Rust type system to suit your specific memory architecture.
Key Takeaway: The Unpin trait is a marker that allows movement; by opting out (!Unpin) and using Pin, you can safely create self-referential structures that are guaranteed to remain stationary in memory.