北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

FutureとUnpin

FutureUnpin が必要なときは 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

BoxUnpin なので、 Pin する必要ないのではと一瞬考える。

boxed.rs.html -- source

impl<T: ?Sized> Unpin for Box {}

しかし、残念ながらそれでは駄目で、理由は Box<F>Future になってくれないから。

boxed.rs.html -- source

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 の制限が入っている。

pin.rs.html -- source

impl<P: Deref<Target: Unpin>> Pin

pub fn new(pointer: P) -> Pin

Box して Unpin にしてしまえば、さらにそれを Pin することで Future にできる。 DerefFuture を参照してるだけで十分なのがポイント。

future.rs.html -- source

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 が呼べる。

pin.rs.html -- source

pub fn as_mut(&mut self) -> Pin<&mut P::Target>

めでたしめでたし。