[Rust/WinRT] async/await構文が実装された


Rust/WinRT は2020年4月30日に最初のプレビュー版が公開されたばかりですが, 急速に開発が進んでいます. 特に, 当初は Rust の async/await 構文に対応していなかった (issue 80) のですが, 7月8日のPR 251で async/await 構文が使えるようになりました! async/await は WinRT の特徴のひとつでもあったので, これはうれしいですね. そこで本記事では Rust/WinRT での async/await の使い方をまとめます.

PR251 以前

当初は Rust の async/await 構文に対応していなかったため, IAsyncOperationIAsyncOperationWithProgress のような WinRT の非同期操作を表すオブジェクトが得られたら, .await の代わりに .get() メソッドを用いてブロックしていました.

例えばウェブサイトに GET リクエストを送り, レスポンスを表示するコードはこうでした (import マクロは自明なので省略).

use windows::{
    foundation::Uri,
    web::http::HttpClient,
};

fn main() -> winrt::Result<()> {
    // URL を指定
    let uri = Uri::create_uri("https://www.jma.go.jp/jp/week/333.html")?;

    // HTTP クライアントを起動
    let client = HttpClient::new()?;

    // GET リクエストを送信しレスポンスを取得
    let resp = client.get_string_async(uri)?.get()?; // <- ここでブロックしている
    println!("{}", resp);

    Ok(())
}

PR251 以後

crates.io の最新版は本記事執筆時点 (7月23日) では winrt = "0.7.1" ですが, PR251はこのバージョンの後にマージされたため, このバージョンではまだ await できません. "0.7.2" には取り込まれると思いますが, さしあたり git リポジトリを直接指定して開発版に依存します.

Cargo.toml
[dependencies]
winrt = { git = "https://github.com/microsoft/winrt-rs" }
futures = "0.3"

なお非同期ランタイムとして futures を使います. こうすれば, 上のコードは Rust の async/await 構文を用いて次のように書き直せます.

use windows::{
    foundation::Uri,
    web::http::HttpClient,
};

async fn main_async() -> winrt::Result<()> { // async 関数としてメインの処理を定義
    // URL を指定
    let uri = Uri::create_uri("https://www.jma.go.jp/jp/week/333.html")?;

    // HTTP クライアントを起動
    let client = HttpClient::new()?;

    // GET リクエストを送信しレスポンスを取得
    let resp = client.get_string_async(uri)?.await?; // async 関数中では await できる
    println!("{}", resp);

    Ok(())
}

fn main() -> winrt::Result<()> {
    futures::executor::block_on(main_async())
}

なお, PR251以前の書き方も引き続き可能です. async/await が必要ない場合はその方がお手軽です.

参考文献