Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of moving Pin is confusing #157

Open
doki23 opened this issue May 7, 2022 · 3 comments
Open

Example of moving Pin is confusing #157

doki23 opened this issue May 7, 2022 · 3 comments

Comments

@doki23
Copy link
Contributor

doki23 commented May 7, 2022

In the Pin(4th) chapter, there is an example showing that we cannot move data if we pinned it, and use std::mem::swap to prove it.

pub fn main() {
    let mut test1 = Test::new("test1");
    let mut test1 = unsafe { Pin::new_unchecked(&mut test1) };
    Test::init(test1.as_mut());

    let mut test2 = Test::new("test2");
    let mut test2 = unsafe { Pin::new_unchecked(&mut test2) };
    Test::init(test2.as_mut());

    println!("a: {}, b: {}", Test::a(test1.as_ref()), Test::b(test1.as_ref()));
    std::mem::swap(test1.get_mut(), test2.get_mut());
    println!("a: {}, b: {}", Test::a(test2.as_ref()), Test::b(test2.as_ref()));
}

But the compilation error is about Pin::get_mut :

std::mem::swap(test1.get_mut(), test2.get_mut());
    |                          ^^^^^^^ within `Test`, the trait `Unpin` is not implemented for `PhantomPinned`

It's because the signature is

pub const fn get_mut(self) -> &'a mut T
    where
        T: Unpin,
    {
        self.pointer
    }

while our Test isn't Unpin, I think it has no connection with std::mem::swap, and no move occurs here, right?

@gftea
Copy link

gftea commented Jun 10, 2022

I agree with you, the error is just because it is not Unpin

@cfsamson
Copy link
Contributor

cfsamson commented Jun 22, 2022

while our Test isn't Unpin, I think it has no connection with std::mem::swap, and no move occurs here, right?

You are correct. No move occurs here.

The error is caused by trying to get a mutable/exclusive pointer to T, which in turn makes it impossible to use mem::swap (for example) to move T. Even though the error itself is not caused by mem::swap, it doesn't invalidate the example when viewed in context of the previous examples. It's still impossible to move, but the error doesn't specifically state that's what it's preventing you from.

If you look at the implementation of swap_simple in the standard library (used for swapping smaller objects), you'll actually see in the comments that this method, while safe to use, assumes "exclusive references are always valid to read/write", and the latter is not the case with Pinned !Unpin types.

    // SAFETY: exclusive references are always valid to read/write,
    // including being aligned, and nothing here panics so it's drop-safe.
    unsafe {
        let a = ptr::read(x);
        let b = ptr::read(y);
        ptr::write(x, b);
        ptr::write(y, a);
    }
}

So, while the error occurs when you try to get a mutable/exclusive reference, the reason behind forbidding you to obtain that for !Unpin types is that it would allow you to move them which would invalidate the exact guarantee Pin is giving you.

@doki23
Copy link
Contributor Author

doki23 commented Jun 24, 2022

It makes sense to me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants