Confusing pin example

One of the examples in the documentation for std::pin has the following lines:

let mut boxed = Box::pin(res);

let slice = NonNull::from(&boxed.data);
// we know this is safe because modifying a field doesn't move the whole struct
unsafe {
    let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed);
    Pin::get_unchecked_mut(mut_ref).slice = slice;
}

Certainly Pin::get_unchecked_mut is unsafe, but why is the call to Pin::as_mut in an unsafe block? This seems to imply that the operation is unsafe, but I don't think it is?

You're correct that Pin::as_mut is a safe function. Here it's in the unsafe block not because it has to be, but because it's only required to be.

You could theoretically write that as

Pin::get_unchecked_mut(Pin::as_mut(&mut boxed)).slice = slice;

but that's a lot of code on a line. Additionally, the example wants to show the type of what it binds to mut_ref, so it pulls that value out into its own binding.

The binding is then put where the scope of the binding is only as long as is necessary; thus, inside the unsafe block.

1 Like

I guess the main reason why it is in the unsafe block is probably to show that the scope of mut_ref does not need to outlive the block. This could be done like:

let mut boxed = Box::pin(res);
let slice = NonNull::from(&boxed.data);

{
    let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed);
    // we know this is safe because modifying a field doesn't move the whole struct
    unsafe { Pin::get_unchecked_mut(mut_ref).slice = slice; }
}

But I think it's still better as-is.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.