Serde: Rustシリアライズ・デシリアライズフレームワーク

Serde はRustエコシステムの中核ライブラリであり、効率的で汎用的なシリアライゼーションとデシリアライゼーションのフレームワークを提供します。その名称は「Serialization」と「Deserialization」の組み合わせに由来しています。

主な特徴

  • 汎用性: JSON、YAML、TOML、MessagePackなど、多様なデータフォーマットをサポート
  • ゼロコスト抽象化: コンパイル時に生成されるコードは手書きコードと同等の効率性
  • 柔軟性: シリアライズ・デシリアライズの動作をカスタマイズ可能
  • 強力な型システム: Rustの型システムを活用してデータの完全性を確保
  • 広範な適用: Rustエコシステムにおけるデータ交換の標準ライブラリとして定着

動作原理

Serdeの中核は中間表現(Intermediate Representation)設計にあり、シリアライズとデシリアライズのプロセスを2段階に分けます:

  1. シリアライズ: Rustデータ構造を汎用中間表現に変換し、その後対象フォーマットに変換
  2. デシリアライズ: 入力フォーマットを汎用中間表現に変換し、その後Rustデータ構造に変換

この設計により、Serdeを使用するアプリケーションを変更することなく、新しいデータフォーマットを追加することが可能です。

基本的な使用方法

依存関係の設定

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" # またはserde_yaml、tomlなどの他のフォーマットライブラリ

導出マクロの使用

最も一般的な使用方法は、構造体に対してシリアライズとデシリアライズの特性を自動的に実装する導出マクロを使用することです:

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug)]
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let point = Point { x: 1, y: 2 };

    // PointをJSON文字列に変換
    let serialized = serde_json::to_string(&point).unwrap();
    println!("シリアライズ結果: {}", serialized); // 出力: {"x":1,"y":2}

    // JSON文字列をPointに戻す
    let deserialized: Point = serde_json::from_str(&serialized).unwrap();
    println!("デシリアライズ結果: {:?}", deserialized); // 出力: Point { x: 1, y: 2 }
}

属性によるカスタマイズ

Serdeはシリアライズ動作をカスタマイズするための豊富な属性を提供します:

#[derive(Serialize, Deserialize, Debug)]
struct User {
    #[serde(rename = "user_id")]
    id: u64,
    
    #[serde(default)]
    name: String,
    
    #[serde(skip_serializing_if = "Option::is_none")]
    email: Option<String>,
    
    #[serde(skip)]
    temporary_data: usize,
}

サポートされるデータフォーマット

Serdeは多様なデータフォーマットと統合されており、各フォーマットには独立したcrateが存在します:

  • serde_json: JSONフォーマット
  • serde_yaml: YAMLフォーマット
  • toml: TOMLフォーマット
  • bincode: バイナリフォーマット
  • postcard: スペース最適化されたバイナリフォーマット
  • rmp/rmp-serde: MessagePackフォーマット
  • ciborium: CBORフォーマット
  • ...その他のフォーマット

高度な使用方法

特性の手動実装

特殊な要件がある場合、SerializeおよびDeserialize特性を手動で実装できます:

use serde::{Serialize, Serializer, Deserialize, Deserializer};

struct MyType {
    // フィールド...
}

impl Serialize for MyType {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        // カスタムシリアライズロジック
    }
}

impl<'de> Deserialize<'de> for MyType {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        // カスタムデシリアライズロジック
    }
}

型マッピング

異なるデータ表現間でマッピングを作成できます:

#[derive(Serialize, Deserialize)]
#[serde(remote = "chrono::DateTime<chrono::Utc>")]
struct DateTimeRef {
    #[serde(with = "chrono::serde::ts_seconds")]
    pub inner: chrono::DateTime<chrono::Utc>,
}

学習とリソース

Serdeは機能豊富なライブラリであり、本記事では基礎のみをカバーしています。Serdeを最大限に活用するためには、以下のことをお勧めします:

  1. Serde公式ドキュメントを訪問して詳細なAPIと例を確認
  2. GitHubリポジトリを参照してソースコードと最新の更新を取得

結び

SerdeはRustエコシステムにおける基盤ライブラリとして、データ交換に強力で柔軟なツールを提供します。Serdeを習得することで、様々なフォーマットのデータ交換要件を容易に処理でき、アプリケーションをより強力で相互運用可能にすることができます。