I'm working on a project involving C FFI where the C side has to store a pointer to a struct created and owned by the Rust side. For this case I ended up using Pin<Arc<T>>
, which seems to fit the bill quite well.
However, it seems that once pinned there is no way to access the Arc
itself, which I need for a few methods it provides (such as Arc::get_mut
and Arc::ptr_eq
).
This has led me to create these few utility functions:
fn pin_get_ptr<P>(pin: &Pin<P>) -> &P {
// SAFETY: Pin is repr(transparent), and we are not moving anything
unsafe { &*(pin as *const _ as *const P) }
}
unsafe fn pin_get_ptr_unchecked_mut<P>(pin: &mut Pin<P>) -> &mut P {
// SAFETY: Pin is repr(transparent). The caller is responsible to ensure the data will never be
// moved, similar to Pin::get_unchecked_mut
unsafe { &mut *(pin as *mut _ as *mut P) }
}
fn arc_get_pin_mut<T>(pin: &mut Pin<Arc<T>>) -> Option<Pin<&mut T>> {
// SAFETY: Arc::get_mut does not move anything
let arc = unsafe { pin_get_ptr_unchecked_mut(pin) };
let inner = Arc::get_mut(arc)?;
// SAFETY: By using get_mut we guaranteed this is the only reference to it.
// The &mut Pin<Arc<T>> argument guarantees this data was pinned, and the temporary Arc reference
// is never exposed.
unsafe { Some(Pin::new_unchecked(inner)) }
}
My main question is: are those functions sound? They seem sound to me, and Miri doesn't seem to complain (although I don't think it knows about pinning guarantees at all), but since exposing the inner pointer of a Pin
is not something that I see done very often, I would like some additional opinions on this.
Assuming this is sound, I am also wondering if this functionality would be desirable to have in the standard library directly. I'm not sure if being unable to access the pointer type itself is a design decision, or simply a case of "there hasn't been much demand yet"?
Thanks in advance!