-
fn new(P) -> Pin<P> where P: Deref, P::Target: Unpin
- This is a safe method to construct
Pin<P>
, and while the existence ofPin<P>
normally means thatP::Target
will never be moved again in the program,P::Target
implementsUnpin
which is read "the guarantees ofPin
no longer hold". As a result, the safety here is because there's no guarantees to uphold, so everything can proceed as usual.
- This is a safe method to construct
-
unsafe fn new_unchecked(P) -> Pin<P> where P: Deref
-
Unlike the previous, this function is
unsafe
becauseP
doesn't necessarily implementUnpin
, soPin<P>
must uphold the guarantee thatP::Target
will never move ever again afterPin<P>
is created.A trivial way to violate this guarantee, if this function is safe, looks like:
fn foo<T>(mut a: T, b: T) { Pin::new_unchecked(&mut a); // should mean `a` can never move again let a2 = mem::replace(&mut a, b); // the address of `a` changed to `a2`'s stack slot }
Consequently it's up to the user to guarantee that
Pin<P>
indeed meansP::Target
is never moved again after construction, so it'sunsafe
!
-
-
fn as_ref(&Pin<P>) -> Pin<&P::Target> where P: Deref
-
Given
Pin<P>
we have a guarantee thatP::Target
will never move. That's part of the contract ofPin
. As a result it trivially means that&P::Target
, another "smart pointer" toP::Target
will provide the same guarantee, so&Pin<P>
can be safely translate toPin<&P::Target>
.This is a generic method to go from
Pin<SmartPointer<T>>
toPin<&T>
-
-
fn as_mut(&mut Pin<P>) -> Pin<&mut P::Target> where P: DerefMut
-
I believe the safety here is all roughly the same as the
as_ref
above. We're not handing out mutable access, just aPin
, so nothing can be easily violated yet.Question: what about a "malicious"
DerefMut
impl? This is a safey way to call a user-providedDerefMut
which crates&mut P::Target
natively, presumably allowing it to modify it as well. How's this safe?
-
-
fn set(&mut Pin<P>, P::Target); where P: DerefMut
- Question: Given
Pin<P>
(and the fact that we don't know anything aboutUnpin
), shouldn't this guarantee thatP::Target
never moves? If we can reinitialize it with anotherP::Target
, though, shouldn't this be unsafe? Or is this somehow related to destructors and all that?
- Question: Given
-
unsafe fn map_unchecked<U, FnOnce(&T) -> &U>(Pin<&'a T>, f: F) -> Pin<&'a U>
-
This is an
unsafe
function so the main question here is "why isn't this safe"? An example of violating guarantees if this were safe looks like:...
Question:: what's the counter-example here? If this were safe, what's the example that shows violating the guarantees of
Pin
?
-
-
fn get_ref(Pin<&'a T>) -> &'a T
-
The guarantee of
Pin<&T>
means thatT
will never move. Returning&T
doesn't allow mutation ofT
, so it should be safe to do while upholding this guarantee.One "maybe gotcha" here is interior mutability, what if
T
wereRefCell<MyType>
? This, however, doesn't violate the guarantees ofPin<&T>
because the guarantee only applies toT
as a whole, not the interior fieldMyType
. While interior mutability can move around internals, it still fundamentally can't move the entire structure behind a&
reference.
-
-
fn into_ref(Pin<&'a mut T>) -> Pin<&'a T>
Pin<&mut T>
means thatT
will never move. As a result it meansPin<&T>
provides the same guarantee. Shouldn't be much issue with this conversion, it's mostly switching types.
-
unsafe fn get_unchecked_mut(Pin<&'a mut T>) -> &'a mut T
Pin<&mut T>
means thatT
must never move, so this is triviallyunsafe
because you can usemem::replace
on the result to moveT
(safely). Theunsafe
here "although I am giving you&mut T
, you're not allowed to ever moveT
".
-
unsafe fn map_unchecked_mut<U, F: FnOnce(&mut T) -> &mut U>(Pin<&'a mut T>, f: F) -> Pin<&'a mut U>
- I think the
unsafe
here is basically at least the same as above, we're handing out&mut T
safely (can't require an unsafe closure) which could easily be used withmem::replace
. There's probably other unsafety here too with the projection, but it seems reasonable that it's at least unsafe because of that.
- I think the
-
fn get_mut(Pin<&'a mut T>) -> &'a mut T where T: Unpin
- By implementing
Unpin
a type says "Pin<&mut T>
has no guarantees, it's just a newtype wrapper of&mut T
". As a result, with no guarantees to uphold, we can return&mut T
safely
- By implementing
-
impl<P: Deref> Deref for Pin<P> { type Target = P::Target }
- This can be safely implemented with
as_ref
followed byget_ref
, so the safety of this impl follows from the above.
- This can be safely implemented with
-
`impl<P: DerefMut> DerefMut for Pin
where T::Target: Unpin { }
- This can be safely implemented with
as_mut
followed byget_mut
, so the safety of this impl follows from the above.
- This can be safely implemented with
-
impl<T: ?Sized> Unpin for Box<T>
(and other pointer-related implementations)-
If no other action were taken,
Box<T>
would implement theUnpin
trait only ifT
implementedUnpin
. This implementation here codifies that even ifT
explicitly doesn't implementUnpin
,Box<T>
implementsUnpin
.Question: What's an example for what this is fundamentally empowering? For example, what safe could would otherwise require
unsafe
if this impl did not exist.
-
Created
November 9, 2018 17:08
-
-
Save alexcrichton/b63d017ca6f74e039bad905130f5a5f3 to your computer and use it in GitHub Desktop.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment