Future
で Unpin
が必要なときは pin
してねって書いてある。
Pinning - Asynchronous Programming in Rust
To use a Future or Stream that isn't Unpin with a function that requires Unpin types, you'll first have to pin the value
Box
も Unpin
なので、 Pin
する必要ないのではと一瞬考える。
impl<T: ?Sized> Unpin for Box
{}
しかし、残念ながらそれでは駄目で、理由は Box<F>
が Future
になってくれないから。
impl<F: ?Sized + Future + Unpin> Future for Box<F>
なぜ Box<F>
を Future
にするのに F: Unpin
がいるのかというと、 poll
を呼び出すにはポインタ先の値を Pin
する必要があるが、 Unpin
じゃなければそれはできないから。
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { F::poll(Pin::new(&mut *self), cx) }
実際、 Pin::new
には Unpin
の制限が入っている。
impl<P: Deref<Target: Unpin>> Pin
pub fn new(pointer: P) -> Pin
Box
して Unpin
にしてしまえば、さらにそれを Pin
することで Future
にできる。 Deref
で Future
を参照してるだけで十分なのがポイント。
impl<P> Future for Pin<P> where P: Unpin + ops::DerefMut<Target: Future>
元々 Pin
されてるので、内側の poll
を呼ぶのに苦労はない。
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { Pin::get_mut(self).as_mut().poll(cx) }
DerefMut
であれば as_mut
が使えるので、ここで &mut (dyn Future)
に変換でき、 poll
が呼べる。
pub fn as_mut(&mut self) -> Pin<&mut P::Target>
めでたしめでたし。