JavaScriptな人のためのRustのFuture入門

RustでI/Oを扱うプログラムを書く機会がありました。非同期I/Oのほうがパフォーマンスがよくなるらしく、tokio というフレームワークがよく使われているとのこと。tokio では Future をベースとして非同期処理を書くようです。明るい Future を生み出していけばよいプログラムがかけそうですね :thumbsup: 。しかし、 tokioやFutureがなんもわからんという問題がありました。そこで、JavaScriptのFuture、Promiseと対比させてRustのFutureについてまとめます。


# JavaScriptのPromise
昔のJavaScript(Node.js)では、ファイル読み込みやネットワークアクセス等のI/O待ちが発生するときはコールバックという仕組みを用いていました。人々は辛くなり、ES2015ではPromiseが導入されました。さらにES2017ではasync/awaitが導入され、一層I/Oの処理が書きやすくなりました。

ではまずはJavaScriptで簡単なPromiseを書いてみましょう。

```JavaScript
const promise = new Promise((resolve, reject) => {
    console.log("promise called");
    resolve('success');
});
```

`promise` の中身のコードはPromiseを定義した時点でランタイムにより実行されはじめます。そのため、上記のコードを実行するとすぐに `promise called` と表示されます。

Promise が成功したときの処理は `then`、失敗したときの処理は `catch` でつなげます。50%の確率で成功、50%の確率で失敗する promise を作ってみましょう。

```JavaScript
const promise = new Promise((resolve, reject) => {
    console.log("promise called");
    
    if (Math.random() * 10 < 5) {
        resolve('success');
    } else {
        reject('failure'); 
    }
});

promise
    .then(res => console.log(res))
    .catch(err => console.error(err));
```

[Wandbox で実行する](https://wandbox.org/permlink/krnzv7UJXRWQpti6)

# RustのFuture
JavaScriptのPromiseに対応するオブジェクトはFutureです。

Promise内では、処理が完了したときに `resolve`もしくは`reject`を呼び結果を通知することになっています。一方で、Futureはポーリングモデルを採用しており、`tokio`等の非同期ランタイムがFutureの結果を取得しにいきます。`tokio`はFutureの`poll`メソッドを定期的に呼び出します。`poll`はまだ実行中だったら `Poll::Pending` を、処理が完了したら `Poll::Ready` を返します。

Futureは futures クレート[^futures01]のものを使います。現時点（2019/08/14）では stable 版の Rust で利用できる futures クレートの最新版は 0.1.28 です。

[^futures01]: https://docs.rs/futures/0.1.28/futures/index.html

futures バージョン 0.1 における Future は次のようなシグネチャをもちます[^futures01]

```rust
pub trait Future {
    type Item;
    type Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error>;
}
```

では Promise で書いた処理を Rust で書いてみましょう。 `poll` メソッドを実装すれば OK です。 50% の確率で Future が正常終了し "success" が出力され、 50% の確率で Future がエラー "failure" を返します。

```rust

struct MyFuture;
impl Future for MyFuture {
    type Item = String;
    type Error = String;

    fn poll(&mut self) -> Poll<String, String> {
        println!("poll called");
        
        let mut rng = rand::thread_rng();
        let i: i32 = rng.gen_range(0, 10);
        if i < 5 {
            Ok(Async::Ready("success".to_string()))
        } else {
            Err("failure".to_string())
        }
        
    }
}
```

Rust の Future を実行するには、 Future を executor にわたす必要があります。 futures クレートにも executor があるので、とりあえずこちらを使ってみましょう。

Promise の then は `and_then` に、 catch は `map_err` に対応します。 executor に突っ込む future は `Item = (), Error = ()` にする必要があるため、 `Ok(())` や `()` を返して型を合わせます。

```rust

fn main() {
    let future = (MyFuture{}).and_then(|res| {
        println!("{}", res);
        Ok(())
    }).map_err(|err| {
        println!("{}", err); // () を返す
    });

    // futures クレートの executor
    futures::executor::spawn(future).wait_future().unwrap();
    println!("finished");
}
```

これでも動きますが、wait_future は Future の実行が完了するまでスレッドをブロックしてしまうので、通常は tokio などのランタイムを使います。

```rust
impl Future for MyFuture {
    ...
}

fn main() {
    let future = (MyFuture{}).and_then(|res| {
        println!("{}", res);
        Ok(())
    }).map_err(|err| {
        println!("{}", err); // () を返す
    });

    tokio::run(future);
    println!("finished");
}
```

[Rust Playground で実行する](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=346f92393e4053707e64d2f96f2be31a)


# RustのFutureのFuture
Rust においても async/await が使えるようにするため、 Rust 1.37 で Future が [std::future](https://doc.rust-lang.org/std/future/trait.Future.html) に収録されました。さらに、Rust 1.38 では async/await が stable になる予定です。近い将来には、 std::future の Future が広く使われるようになるでしょう。 tokio も master ブランチでは std::future をデフォルトで使うように開発が進められているようです。

futures 0.1 の Future と futures 0.3 の Future は相互変換できるため、環境を移行するのも難しくはないと思います（希望をこめて）。

futures 0.3 や std::future における Future は次のようなシグネチャを持ちます。

```rust
pub trait Future {
    type Output;
    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output>;
}
```

std::future では成功/失敗の概念を Future から切り離しました。そのため、成功/失敗を表現するためには、Result を返すようにする必要があります。では、さきほどの処理を std::future の Future で書き換えてみましょう。

```rust
struct MyFuture;
impl Future for MyFuture {
    type Output = Result<String, String>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        println!("poll called");
        
        let mut rng = rand::thread_rng();
        let i: i32 = rng.gen_range(0, 10);
        if i < 5 {
            Poll::Ready(Ok("success".to_string()))
        } else {
            Poll::Ready(Err("failure".to_string()))
        }
    }
}
```

この Future を実行するには、 Future を executor にわたす必要があります。 ひとまずは [futures::executor::block_on](https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.18/futures/executor/fn.block_on.html) を使ってみましょう。`and_then` はもとの Future と同じ型を返す必要がありますが、 `map_ok` ではもとの Future と違う型を返すことができます。


```rust
let future = (MyFuture{}).map_ok(|res| {
    println!("{}", res);
}).map_err(|err| {
    println!("{}", err);
});
let _ = block_on(future);
```

futures 0.3 では `ThreadPool` という executor もあります。`ThreadPool` は複数のスレッドを用いて Future を実行してくれるため、通常はこちらの executor を使ったほうがいいと思います。いずれは tokio 等のランタイムでも気軽に std::future も使えるようになるでしょう。

```rust
fn get_future() -> impl Future<Output=Result<(), ()>> {
    (MyFuture{}).map_ok(|res| {
        println!("{}", res);
    }).map_err(|err| {
        println!("{}", err);
    })
}

let future = get_future();
ThreadPool::new().expect("Failed to create threadpool").run(future);
```


Future の途中結果を print したいことは多々あると思います。このために、 `inspect_ok` や `inspect_err` が提供されています[^futures-03-inspect]。 print するだけだったら map ではなくて inspect を使ったほうがいいでしょう。

```rust
let future = (MyFuture{}).inspect_ok(|res| {
    println!("{}", res); 
}).inspect_err(|err| {
    println!("{}", err);
});

let _ = block_on(future);
```

[^futures-03-inspect]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.18/futures/future/trait.TryFutureExt.html#method.inspect_ok

ソースコードの全文は [Github](https://github.com/Kumassy/qiita-rust-future/tree/master/std-future) にあります。

## ドキュメントについて
Rust に async/await を取り入れるためには、Future を言語のコア機能に取り入れる必要がありました。一方で、言語のコア機能に Future を取り入れてしまうと、 Future の変更が困難になってしまいます。そのため、 std::future::Future の機能は最小限になっています。
https://doc.rust-lang.org/std/future/index.html

Future の便利機能は今後も futures クレートで提供されるようです。std::future と互換性がある futures 0.3 のドキュメントを参照してください。
https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.18/futures/index.html

`then` 等の便利メソッドは [FutureExt トレイト](https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.18/futures/future/trait.FutureExt.html)で提供されます。これは `use futures::FutureExt` すると使えるようになります。


`type Output = Result<String, String>` のように Future の値を `Result` 型にした場合、 `use TryFuture` とすると [TryFuture トレイト](https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.18/futures/future/trait.TryFuture.html) の機能が利用できるようになります。
また、 `use futures::TryFutureExt` すると、 [TryFutureExt トレイト](https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.18/futures/future/trait.TryFutureExt.html) の機能が使えるようになります。`map_ok` や `inspect_err` はこちらで定義されています。

# まとめ
この記事では JavaScript の Promise と対比させて、Rust の Future について解説しました。 Rust の Future はポーリングモデルを採用し、ランタイムが `poll` を呼び出すことで処理が進んでいきます。

Future には 0.1 系と 0.3 系があり、近い将来は 0.3 系が広く使われていくかと思いますが、これらは相互変換できます。現状は tokio 等のランタイムがデフォルトでサポートしており、ドキュメントの多い 0.1 系を使っていくのがいいでしょう。

ツッコミ、感想等コメントお待ちしています :sunglasses:


# 謝辞
この記事の一部は @__pandaman64__ 氏に助言をいただき執筆しました。この場を借りて謝意を表します。