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.