Zenn
📝

StateStruct - structの読み書きを追跡するマクロライブラリを開発している話

2025/03/22に公開

はじめに

https://github.com/VergeGroup/swift-macro-state-struct

StateStructは、Swiftの構造体(struct)内での状態管理をサポートするライブラリです。Swiftマクロとコンパイラプラグインを活用して、プロパティの読み書きを追跡し、依存関係グラフを構築することで、状態の変更を検出します。

主要な機能

1. 依存関係の追跡

  • @Trackingマクロを使用して、プロパティへのアクセスを追跡
  • 読み取り操作:プロパティが読み取られた際に、そのアクセスパスが依存関係グラフに記録
  • 書き込み操作:プロパティが変更された際に、変更グラフに記録

2. 変更検出

  • PropertyNode.hasChanges(writeGraph:readGraph:)関数を使用して、読み取りと書き込みの依存関係グラフを比較
  • 変更があったプロパティを検出し、必要な更新のみを実行

3. ネストされた状態のサポート

  • フラットなプロパティだけでなく、深くネストされた構造体の状態変更も追跡可能にする
    • そのネストされたtypeも@Trackingを持つ必要がある
  • 例:state.nested.nameのような階層構造のプロパティも追跡

4. Copy-on-Write (COW)の実装

  • パフォーマンスを考慮し、Copy-on-Writeメカニズムを実装
    • IntやArrayなど、COWにする必要のないものはknown-typesとして除外される
  • 状態の変更が必要な場合のみコピーを作成

使用例

import StateStruct

@Tracking
struct MyState {
    var height: Int = 0
    var name: String = ""
    var nested: Nested = .init(name: "")

    @Tracking
    struct Nested {
        var name: String = ""
        var age: Int = 18
    }
}

// 状態の追跡を開始
var state = MyState()
state.startNewTracking()

// プロパティの読み取りを追跡
_ = state.height
_ = state.nested.name
let readTracking = state.trackingResult!

// プロパティの書き込みを追跡
state.startNewTracking()
state.height = 200
let writeTracking = state.trackingResult!

// 変更の検出
let hasChanged = PropertyNode.hasChanges(
    writeGraph: writeTracking.graph,
    readGraph: readTracking.graph
)

技術的な仕組み

  1. マクロによるコード生成

    • Swiftマクロを使用して、プロパティアクセスの追跡コードを挿入
    • 追跡に必要なコードを自動生成
  2. 依存関係グラフの構築

    • プロパティアクセス時に、PropertyPathオブジェクトを使用してアクセスパスを記録
    • 読み取りと書き込みの依存関係を別々のグラフとして管理

ユースケース

利用している箇所
https://github.com/VergeGroup/swift-verge/pull/521

Discussion

ログインするとコメントできます