I'm writing a future combinator that needs to consume a value that it was provided with. With futures 0.1, Future::poll
took self: &mut Self
, which effectively meant that my combinator contained an Option
and I called Option::take
on it when the underlying future resolves.
The Future::poll
method in the standard library takes self: Pin<&mut Self>
instead, so I've been reading about the guarantees required in order to safely make use of Pin
.
From the pin
module documentation on the Drop
guarantee (emphasis mine):
Concretely, for pinned data you have to maintain the invariant that its memory will not get invalidated from the moment it gets pinned until when drop is called. Memory can be invalidated by deallocation, but also by replacing a
Some(v)
byNone
, or callingVec::set_len
to "kill" some elements off of a vector.
And Projections and Structural Pinning (emphasis mine):
You must not offer any other operations that could lead to data being moved out of the fields when your type is pinned. For example, if the wrapper contains an
Option<T>
and there is a take-like operation with typefn(Pin<&mut Wrapper<T>>) -> Option<T>
, that operation can be used to move aT
out of a pinnedWrapper<T>
-- which means pinning cannot be structural.
However, the existing Map
combinator calls Option::take
on a member value when the underlying future has resolved:
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
match self.as_mut().future().poll(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(output) => {
let f = self.f().take()
.expect("Map must not be polled after it returned `Poll::Ready`");
Poll::Ready(f(output))
}
}
}
The f
method is generated by the unsafe_unpinned
macro and looks roughly like:
fn f<'a>(self: Pin<&'a mut Self>) -> &'a mut Option<F> {
unsafe { &mut Pin::get_unchecked_mut(self).f }
}
It appears that Map
violates the requirements that are described in the pin
documentation, but I believe that the authors of the Map
combinator know what they are doing and that this code is safe.
What logic allows them to perform this operation in a safe manner?
Pin
only being about stability over suspension points), but... – Leduc