0 day streak
rust / expert
Snippet

Self-Referential Types Using Pin and Pointer Pinning

This snippet demonstrates how to create a self-referential struct in Rust using `Pin` and `PhantomPinned`. Pinning ensures the struct cannot be moved in memory once its internal pointer is initialized, making it safe to store and dereference a raw pointer pointing to its own fields.

snippet.rs
rust
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
use std::marker::PhantomPinned;
use std::pin::Pin;
pub struct SelfReferential {
value: String,
pointer: *const String,
_marker: PhantomPinned,
}
impl SelfReferential {
pub fn new(val: &str) -> Self {
Self {
value: val.to_string(),
pointer: std::ptr::null(),
_marker: PhantomPinned,
}
}
pub fn init(self: Pin<&mut Self>) {
let val_ptr = &self.value as *const String;
unsafe {
let this = self.get_unchecked_mut();
this.pointer = val_ptr;
}
}
pub fn get_referred_value(&self) -> Option<&str> {
if self.pointer.is_null() {
None
} else {
unsafe { Some(&*self.pointer) }
}
}
}
Breakdown
1
_marker: PhantomPinned
Prevents the type from implementing `Unpin`, forcing it to remain pinned in memory once pinned.
2
pub fn init(self: Pin<&mut Self>)
Requires the struct to be wrapped in a `Pin` reference before initialization of the self-referencing pointer.
3
let this = self.get_unchecked_mut()
Accesses the mutable fields of the pinned struct via unsafe code to set up the raw pointer.
4
this.pointer = val_ptr
Stores the memory address of the struct's own `value` field within the `pointer` field.
5
unsafe { Some(&*self.pointer) }
Dereferences the raw pointer safely because pinning guarantees the address has not changed.