rust

Generating an error for Pinned objects in Rust


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.


Solution

  • 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());
    }