Rustの非同期ランタイム `#[tokio::main]`を深堀り

# はじめに
はじめまして、Rust勉強中の人です。
Rustを書き書きしていると度々登場する[手続き型マクロ](https://doc.rust-lang.org/book/ch19-06-macros.html#attribute-like-macros)。
こいつはそれはそれは便利なやつらしいですが、「一体内部で何をしてくれているんだ？」ってなったので、一つ例をとって深堀りしてみようと思った次第です。


# 早速掘り下げてゆく〜
今回は[`actix-web`](https://actix.rs/)で *Hello World!* する下記の簡単なコードを例にとって掘り下げていきます。
```rust:Hello World!
use actix_web::{web, App, HttpServer, Responder};

async fn hello() -> impl Responder {
    "Hello, World!"
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/", web::get().to(hello))
        })
        .bind("127.0.0.1:8000")?
        .run()
        .await
}
```

## 1. `tokio::main`の目的を知る
とりあえず`#[tokio::main]`を削除して`cargo check`を実行してみます。
すると、コンパイラさんが次のエラーを吐きます。

```
error[E0752]: `main` function is not allowed to be `async`
 --> src/main.rs:8:1
  |
8 | async fn main() -> std::io::Result<()> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` function is not allowed to be `async`

For more information about this error, try `rustc --explain E0752`.
error: could not compile `helloworld` due to previous error
```

前提として、[`HttpServer::run`](https://docs.rs/actix-web/4.0.1/actix_web/struct.HttpServer.html)は非同期メソッドです。しかし、バイナリのエントリポイントである`main`は**非同期関数にできません**。ですが、どうにかして`main`を非同期にしなければいけません。

Rustの非同期プログラミングは[`Future`](https://doc.rust-lang.org/beta/std/future/trait.Future.html)トレイトの上に構築されています。`Future`トレイトは`poll`メソッドを実装しており、これを**非同期ランタイム側から呼び出し、非同期タスクをポーリングする**ことで、最終的な値が解決されるという仕組みです。

しかし、Rustは標準ライブラリで、非同期ランタイムをサポートしていません。`Cargo.toml`の`[dependencies]`以下に依存関係として記述して、外部から取り込まなければいけません。
そこで登場するのが、非同期ランタイム **`tokio`** ってわけ。
非同期関数になりえない`main`関数の先頭で非同期ランタイムを起動し、非同期タスクの最終的な値を解決します。

以上が大まかな`#[tokio::main]`の目的・役割になります。


## 2. コードを解剖する
手続き型マクロの主な役割は、入力としてコードを**取り込み**、コードを**生成し**、コンパイラに出力を**渡す**ことです。
この展開後のコードを見ることができれば重要な何かが見えてきそうですが、まさにそれの目的を果たしてくれる便利ツールがあります。

#### ツールをインストール
次の2つを実行して、必要なツールをインストールします。

```: cargo-expand
$ cargo install cargo-expand
```

`cargo-expand`はコード内のマクロを展開しコンパイラに渡さずに、中身を出力してくれます。

```: nightly
$ rustup toolchain install nightly --allow-downgrade
```

`cargo-expand`は多くの方が普段使っているであろう安定版の`stable`コンパイラではなく、 **`nightly`** と呼ばれる毎晩リリースされるコンパイラ（詳しくは[こちら](https://doc.rust-jp.rs/book-ja/appendix-07-nightly-rust.html)）に依存してマクロを展開します。しかし、`nightly`の最新のリリースでは、`rustup`によってインストールされるバンドルのいくつかのコンポーネントが欠けていたり、不具合があったりする可能性があるため、`--allow-downgrade`ですべての必要なコンポーネントが利用可能な最新のリリースを見つけてインストールするように`rustup`に指示します。

`cargo list`、`rustup show`を実行して、インストールされていることが確認できたら、次に進みます。

#### 実行
次を実行します。

```
$ cargo +nightly expand
```

`cargo +[~] [command]`とすることで、コマンド単位でツールチェーンを指定できます。
今回は先程説明したとおり、依存関係にある`nightly`を指定します。
すると、下のようにマクロ展開後のコードが出力されます。

```rust
/// ...

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use actix_web::{web, App, HttpServer, Responder};
async fn hello() -> impl Responder {
    "Hello, World!"
}
fn main() -> std::io::Result<()> {
    let body = async {
        HttpServer::new(|| App::new().route("/", web::get().to(hello)))
            .bind("127.0.0.1:8000")?
            .run()
            .await
    };
    #[allow(clippy::expect_used)]
    tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .build()
        .expect("Failed building the Runtime")
        .block_on(body)
}
```

`#[tokio::main]`の展開後にコンパイラに渡される`main`は同期関数になっている〜！

```rust
tokio::runtime::Builder::new_multi_thread()
    .enable_all()
    .build()
    .expect("Failed building the Runtime")
    .block_on(body)
```

重要なのはこの部分で、
`tokio`の非同期ランタイムを起動し、`main`関数全体の処理を`block_on`することで、`HttpServer::run`が返す`Future`が完了するまでブロックしています。 

***要は、`#[tokio::main]`の役割は、非同期の`main`を定義しているかのように見せかけて、その裏では、非同期のmainを受け取り、tokioのランタイムの上でそれを実行するために必要な定型文に書き換えて、コンパイラに渡してくれているだけってことです！！！***

はい、やりたかったことは以上です。
なんかまとめ方が下手すぎますが、おわりです。

# さいごに
今回がQiitaへの初めての投稿でした。
順序立てて、解説を加えていく中で自分の中での理解もより一層深まった気がします。
また時間を見つけて積極的に投稿していけたらと思っています。

最後まで読んでいただきありがとうございました。


# 参考
今回の記事を書くにあたり、Rustの非同期処理について調べる際、こちらの記事がとても参考になりました。

https://qiita.com/Kumassy/items/fec47952d70b5073b1b7