Sure you can: it's just that the target has to provide its own methods for it. It's perfectly valid (if pointless) to write
struct PracticallyUnpin(..., PhantomPinned);
impl PracticallyUnpin {
fn unpin_mut(self: Pin<&mut Self>) -> &mut Self {
// SAFETY: We're the ones writing the rules here
unsafe { Pin::into_inner_unchecked(self) }
}
...
// (no other unsafe methods or impls)
}
and then the caller can do whatever they want with that reference, e.g., moving the value. Unpin isn't a magic word: it's just a generic way for the target to indicate that pinned pointers can safely regain full capabilities.Of course, putting a Pin around an object does further restrict what you can do with it generically in unsafe code. But I'd further count these under the umbrella of "intrinsic unsafe capabilities", which Pin removes, but which the target can later restore ad libitum. Compare the question of whether a fn replace_with(&mut T, impl FnOnce(T) -> T) (aborting on panic) is sound, which really comes down to the "unsafe capabilities" of a &mut reference.
This is not to say, of course, that the target need not be very circumspect about which capabilities it restores! It has a responsibility not to create an unsound interface that might result in UB under permitted usage. E.g., if we have a type that owns a generic non-Unpin future, then that type must follow the strictest Pin invariants w.r.t. that future. But otherwise, it's entirely up to the target type which capabilities it wants to restore under which circumstances.