I am looking at self-referencing structs and I understand how the Sync/Send trait are used to force safety from race conditions, but the Pin use case seems poorly explained.
Basically, this code doesn't not compile because iter
is not Send:
fn main() {
let mut list : LinkedList<RefCell<String>> = LinkedList::new();
list.push_back(RefCell::new("foo".to_string()));
let iterator = list.iter();
thread::spawn(move || {
// Compiler error: iterator is not Send.
for item in iterator {
item.replace("qux".to_string());
}
}).join().unwrap();
}
Is there similar code that doesn't compile because the object to be moved is not Pin or Pin is just a convention that says to the receiving code that the object is sent in a consistent state? Examples out there seem to imply a compiling error, but never been able to see one generated that was obviously due to pinning issues.
To better rephrase the question: Violating Send requirements causes compilation errors. Is it possible to generate compilation errors by violating a Pin contract? I've read that moving an object that requires pinning while not pinned causes an error but I couldn't find a way to cause a compilation error that disappears when the object is pinned.
So ok, I've found it in the official async documentation.
Basically this is a pseudo minimalistic example of compilation error when the comments are removed from the lines containing _marker.
use std::pin::Pin;
use std::marker::PhantomPinned;
#[derive(Debug)]
struct Test {
a: String,
// _marker: PhantomPinned, // remove comment for compilation error
}
impl Test {
fn new(txt: &str) -> Self {
Test {
a: String::from(txt),
// _marker: PhantomPinned, // remove comment for compilation error
}
}
}
pub fn main() {
let mut test1 = Test::new("test1");
let mut test1 = unsafe { Pin::new_unchecked(&mut test1) };
let mut test2 = Test::new("test2");
let mut test2 = unsafe { Pin::new_unchecked(&mut test2) };
// the following line won't compile
std::mem::swap(test1.get_mut(), test2.as_mut().get_mut());
}