文字列ユニオンからのRust enum

JSON値が固定セットから取られる場合、String フィールドを型付きRust enum に置き換えます。serde 互換を保ちつつコンパイル時の網羅性を得られます。

Type Mapping

詳細な説明

String フィールドを serde 対応 enum に昇格する

JSONのフィールドが常に固定セットの文字列("active""inactive""banned")のいずれかを取る場合、生成された String フィールドを Rust の enum に置き換えられます。コンパイラがすべての match アームの処理を強制してくれます。

JSONの例

{
  "id": 1,
  "name": "Ada",
  "status": "active"
}

生成されるRust(初期状態)

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
    pub id: i32,
    pub name: String,
    pub status: String,
}

enum へ昇格

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Status {
    Active,
    Inactive,
    Banned,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Root {
    pub id: i32,
    pub name: String,
    pub status: Status,
}

rename_all が必要な理由

#[serde(rename_all = "lowercase")] がないと、serde は JSON 側で "Active"(バリアント名と同じ綴り)を期待してしまいます。多くの API は小文字や snake_case を使うため、rename_all で JSON 契約を保ちつつ Rust 側は PascalCase の慣用表記を維持できます。

その他のリネーム戦略

属性 JSON 上の表現
"lowercase" active
"UPPERCASE" ACTIVE
"snake_case" active_user
"SCREAMING_SNAKE_CASE" ACTIVE_USER
"kebab-case" active-user

バリアントエイリアス

API が同じ論理値に対して複数の綴りを返す場合、バリアント単位でリネームできます。

pub enum Role {
    #[serde(rename = "admin")]
    Administrator,
    #[serde(rename = "user", alias = "regular")]
    Regular,
}

未知の値を捕捉する

サーバ側で新しい値が追加されたときにクラッシュしないよう、フォールバック用のバリアントを用意しておきましょう。

#[serde(other)]
Unknown,

これで、APIに新しいステータスが追加されてもクライアントがクラッシュすることはありません。

ユースケース

注文ステータス、ユーザロール、決済状態、イベント種別は典型的な enum 候補です。Rust の網羅的 match と serde のリネーム属性を組み合わせれば、ゼロランタイムコストでコンパイル時安全性が手に入ります。

試してみる — JSON to Rust Struct Converter

フルツールを開く