rodrigocfd
rodrigocfd

Reputation: 8053

Will a PhantomPinned member make my struct have a fixed memory address?

I'm writing Rust code which communicates with a C API, and I need a certain struct to have a fixed memory address. So far, I found:

If I understood correctly, PhantomPinned would be the easiest to use: just having it as a member would make my struct automatically have a fixed memory address. Is this correct?

Upvotes: 3

Views: 1293

Answers (2)

Chayim Friedman
Chayim Friedman

Reputation: 70990

What you need is Pin. It's a pointer that keeps your object from being moved.

pin_mut!() is just a macro that helps you create a Pin instance without heap allocation or unsafe code.

PhantomPinned has another, though related, goal. By default, your type will implement the Unpin trait (unless it contains a type that don't implement Unpin, however most types do). This is problematic, because for types that implements Unpin, Pin has no effect: it does not prevent you from moving them. This is because most types do not need a fixed memory address. Think about i32, for example: even if you create Pin<&mut i32>, you can move it, because i32 implements Unpin, because even if you'll move it nothing bad will happen, and no data will be validated.

So for Pin to be effective you need to un-impl Unpin. This is done by either including a field that doesn't implements Unpin itself as a field, or having a negative impl (see What is an auto trait in Rust?):

impl !Unpin for MyType {}

Unfortunately, negative impls are unstable. Instead, the standard library provides the PhantomPinned type, which is costless (a ZST), but doesn't implement Unpin (it has a negative impl, since the standard library is allowed to use unstable features it can do that). And now when your type includes it it becomes !Unpin too.

To sum up, you need to include PhantomPinned in your struct so it will not be Unpin, and you need to wrap it in Pin so it will be unmovable.

Upvotes: 6

Colonel Thirty Two
Colonel Thirty Two

Reputation: 26569

The only unmoveable value in Rust is the value in Pin<T> and only if T does not implement Unpin.

T may be a reference or some smart pointer type like Box or Arc, but Pin is needed to specify that the value may not move.

Unpin is a trait implemented for types that don't care if they are moved, even if they are pinned. It's a marker trait automatically implemented for all types whose members all implement Unpin. PhantomPinned is a simple, zero sized type that does not implement Unpin, so it may be added to a struct or enum to make it not automatically implement Unpin.

Note that Unpin is only relevant to Pin wrapped values - values outside of Pin can still be moved. Operations requiring the value not be moved should take a Pin<&mut T> instead of &mut T.

pin_mut is a macro for converting a stack value to a pinned pointer. It's just a convenience for a known-safe case and doesn't really play into how Pin works.


So for your case, it sounds like your structure should have a PhantomPinned member, and all of its operations should take a pin-wrapped reference.

Upvotes: 1

Related Questions