Skip to content
Published on

Rustエコシステム巡り:素晴らしいクレートとプロジェクト

Authors

はじめに — 言語よりエコシステム

Rustを語るとき、私たちはたいてい所有権、借用チェッカー、メモリ安全性といった言語の特徴を真っ先に思い浮かべます。しかし、ある言語が実務で使えるかを決めるのは文法だけではありません。必要な仕事をすでにうまくこなすライブラリがあるか、それをどれだけ簡単に取り込めるか、つまりエコシステムの成熟度が肝心です。

Rustはこの点で、ここ数年で劇的に成長しました。2015年の1.0リリース以降、crates.ioには数十万のクレートが積み上がり、そのいくつかは各分野の事実上の標準になっています。本記事は、その代表的なクレートと有名プロジェクトを一巡りする地図です。各クレートが「何のためのものか」に焦点を当てるので、Rustで何かを始めるときにどこを見ればよいか、感覚をつかむのに役立つはずです。

cargoとcrates.io — エコシステムの土台

クレートの話をする前に、それを可能にする土台から押さえるべきです。Rustのエコシステムが素早く成熟した背景には、最初からよく作られたツールチェーンが大きく寄与しています。

cargoはRustの公式ビルドツールであり、パッケージマネージャーです。プロジェクト作成(cargo new)、ビルド(cargo build)、テスト(cargo test)、実行(cargo run)、依存関係の管理を、一つの一貫したコマンドで処理します。ビルドツールとパッケージマネージャー、フォーマッター、テストランナーがばらばらな言語と比べると、一つに統合された体験は参入障壁を大きく下げます。

crates.ioは公開クレートレジストリです。Cargo.tomlにクレート名とバージョンを書くだけで、cargoが自動でダウンロードしてビルドします。これにセマンティックバージョニングとロックファイル(Cargo.lock)が組み合わさり、再現可能なビルドが既定で保証されます。

[dependencies]
serde = { version = "1", features = ["derive"] }
tokio = { version = "1", features = ["full"] }

このシンプルな宣言一つで、ライブラリとその推移的な依存関係すべてが付いてきます。以下で紹介するすべてのクレートは、結局この二つのツールの上に載っています。

基礎クレート — serdeとtokio

Rustのプロジェクトを開くと、ほぼ必ず登場する二つのクレートがあります。エコシステムの底を支える柱と言えるものです。

serdeはシリアライズ/デシリアライズのフレームワークです。構造体に導出マクロを付けるだけで、JSON、YAML、TOML、MessagePackなど数多くのフォーマットと相互変換されます。核心となる設計は「データモデル」と「フォーマット」を分離したことで、同じ型を複数のフォーマットで扱えるようにしてくれます。

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
struct Config {
    name: String,
    port: u16,
}

// この型はJSON、YAML、TOMLなどと自由に行き来する
let cfg: Config = serde_json::from_str(r#"{"name":"web","port":8080}"#)?;

tokioはRustの非同期ランタイムです。Rustはasync/await構文を言語に持ちつつ、実際にそのタスクをスケジューリングして実行するランタイムはライブラリに委ねます。tokioはそのランタイムの事実上の標準で、非同期タスクスケジューラ、ノンブロッキングI/O、タイマー、チャネルなどを提供します。以下で見るネットワーク・Web・DBクレートの多くがtokioの上で動きます。

#[tokio::main]
async fn main() {
    let handle = tokio::spawn(async {
        // 同時に実行される非同期タスク
        "done"
    });
    println!("{}", handle.await.unwrap());
}

並列性とデータ — rayonとpolars

Rustの強みの一つが「恐れなき並行性(fearless concurrency)」です。型システムがデータ競合をコンパイル時に防いでくれるので、並列コードをずっと安心して書けます。この強みを最もよく示すクレートがrayonです。

rayonはデータ並列(data parallelism)のライブラリです。驚くのは使い方の単純さです。逐次イテレータ(iter)を並列イテレータ(par_iter)に変えるだけで、コレクションの処理が複数コアに自動で分散されます。

use rayon::prelude::*;

// iter() -> par_iter() の一語違いで並列処理
let sum: u64 = (0..1_000_000)
    .into_par_iter()
    .filter(|n| n % 3 == 0)
    .map(|n| n as u64)
    .sum();

内部では作業窃取(work-stealing)スケジューラが負荷をコアに均等に分けます。並列化の正しさはRustの型システムが保証するので、データ競合を心配せず性能だけを追えます。

polarsは高性能なデータフレームライブラリです。Pythonのpandasに対応する位置づけですが、Apache Arrowベースの列指向ストレージと遅延評価(lazy evaluation)、クエリ最適化を組み合わせ、大容量データで非常に高速です。Rustから直接使えるほか、Pythonバインディングとしても広く使われ、データ分析の陣営で存在感を増しています。

ネットワークとWeb — reqwest、hyper、axum

Webはどの言語でも大きな領域で、Rustではこの層がよく整理されています。

hyperは低レベルなHTTPライブラリです。HTTP/1とHTTP/2を正確かつ高速に実装した土台で、クライアントとサーバーの両方を支えます。直接使うには低レベルですが、以下の上位クレートがhyperの上に載っています。

reqwestはhyperを包んだ使いやすいHTTPクライアントです。JSONのリクエスト/レスポンス、クッキー、リダイレクト、TLSを簡潔なAPIで扱います。「別のサービスのAPIを呼ぶ」という日常的な作業で、真っ先に手が伸びるクレートです。

let body: serde_json::Value = reqwest::get("https://api.example.com/status")
    .await?
    .json()
    .await?;

axumはtokioチームが作ったWebフレームワークです。hyperとtower(ミドルウェアの抽象化)の上に立ち、ルーティングとリクエストのパースを型安全な「エクストラクタ(extractor)」方式で表現します。マクロに頼らず、ふつうの関数と型でハンドラを書く設計が特徴です。

use axum::{routing::get, Router};

async fn hello() -> &'static str {
    "Hello, world!"
}

let app = Router::new().route("/", get(hello));

データベースとCLI — sqlx、diesel、clap

アプリケーションなら、たいていデータベースとコマンドラインインターフェースが必要です。Rustにはこの二つのための成熟した選択肢があります。

データベースアクセスには代表的に二つの流派があります。sqlxは非同期SQLツールキットで、興味深いことに、コンパイル時にSQLクエリを実際のデータベーススキーマと照合して検査します。つまり、誤った列名や型の不一致をビルド段階で捕まえます。一方、dieselは完全なORMかつクエリビルダーで、Rustのコードで型安全にクエリを組み立てます。sqlxはSQLを直接書きつつ検証したいとき、dieselはORMスタイルの抽象化がほしいときに向いています。

clap(Command Line Argument Parser)はコマンドライン引数パースの事実上の標準です。構造体に導出マクロを付ければ、引数の定義からパーサーとヘルプ、サブコマンドまで自動で生成してくれます。

use clap::Parser;

#[derive(Parser)]
struct Cli {
    /// 処理する入力ファイル
    path: String,
    /// 詳細出力を行うか
    #[arg(short, long)]
    verbose: bool,
}

let cli = Cli::parse(); // --help も自動生成される

グラフィックスとアプリ — Bevy、wgpu、Tauri

システム言語らしく、Rustはグラフィックスやアプリケーションの領域でも興味深いプロジェクトを生み出してきました。

wgpuはクロスプラットフォームのグラフィックスAPIです。ブラウザ標準のWebGPUを基盤とし、その背後でVulkan、Metal、DirectX 12といった各プラットフォームのネイティブなグラフィックスバックエンドへつながります。一つのコードで複数プラットフォームのGPUを扱える移植性が強みです。

BevyはRustで書かれたゲームエンジンです。ECS(Entity Component System)アーキテクチャを前面に押し出したのが特徴で、データ指向設計とRustの並列性がうまく噛み合います。オープンソースで活発に開発され、ゲームだけでなくシミュレーションやインタラクティブなアプリケーションにも使われます。

Tauriはデスクトップ(およびモバイル)アプリを作るフレームワークです。Electronと目的は似ていますが、アプローチが異なります。ElectronがアプリごとにChromiumブラウザ全体をバンドルするのに対し、Tauriはオペレーティングシステムが提供するシステムWebViewを使い、バックエンドをRustに置きます。その結果、バイナリサイズとメモリ使用量がはるかに小さくなります。フロントエンドは慣れたWeb技術で書き、重いロジックとシステムアクセスはRustが担う構造です。

有名プロジェクト — Rustが世界に残したもの

クレートが部品なら、その部品で作られた完成品もRustの地位をよく示します。いくつかの広く知られたプロジェクトを見てみましょう。

  • ripgrep(rg): Rustで書かれた超高速のコード検索ツールです。正規表現エンジンと並列走査、.gitignoreの認識を組み合わせ、大規模なコードベースで驚くべき速度を出します。多くの開発者がgrepの代わりに日常的に使い、VS Codeの検索機能も内部でripgrepを使っています。
  • Deno: Node.jsの生みの親が作ったJavaScript/TypeScriptランタイムです。コアはRustで書かれ、V8エンジンを内包します。既定でのセキュリティ(権限モデル)、TypeScriptの標準サポートなどを打ち出しています。
  • Firecracker: AWSが作った軽量な仮想化技術(microVM)です。Rustで書かれ、サーバーレス(AWS Lambda)やコンテナサービスの隔離基盤として使われます。数十ミリ秒で立ち上がる軽量なVMで、セキュアな隔離と高速な起動を同時に狙います。
  • LinuxカーネルのRustサポート: 2022年のLinux 6.1から、カーネルでRustを使うための基盤がマージされました。数十年にわたりCが支配してきた領域にRustが入った象徴的な出来事で、主に新しいドライバなどでメモリ安全性を得ようとする試みです。

このほかにも、Firefoxの各種構成要素、パッケージングツール、Webサーバー、ブロックチェーン、組み込みなど、多くの分野でRustが使われています。共通点は「性能と安全性が同時に重要な場所」で特に強いことです。

自分で触ってみる

ここまで見てきたクレートやプロジェクトは、結局Rustという言語の土台の上に立っています。所有権、トレイト、列挙型といった概念に手を慣らすと、このエコシステムがなぜこの形なのかがより見えてきます。Rustの核心概念を自分でコードとして実験したいなら、当サイトのRust学習ラボで扱えます。また、RustはWebAssembly陣営の主力言語でもあり、wgpuがWebGPUを基盤にするように、WebはRustの重要な舞台です。WebAssemblyがどう動くのか気になるなら、WebAssemblyの原理でその構造を見られます。

おわりに

Rustの力は言語一つにとどまりません。cargoとcrates.ioというよく作られた土台の上に、serdeやtokioのような基礎クレート、rayonやpolarsのようなデータ・並列ツール、reqwest・hyper・axumへとつながるWeb層、sqlx・diesel・clapのようなアプリケーションの部品、そしてBevy・wgpu・Tauriのようなグラフィックスとアプリのフレームワークが層をなして積み上がっています。

そしてその部品から、ripgrep、Deno、Firecrackerのような実際のツールが作られ、ついにはLinuxカーネルにまでRustが足を踏み入れました。これらすべてを貫く共通点は、Rustが「速くて、しかも安全な」コードを求める場所で特に輝くという事実です。

新しく何かを始めるとき、この地図がどこを先に見ればよいかを教える道標になれば幸いです。必要なクレートはたいていすでに存在し、cargoの一行で手に入ります。

参考資料