もんりぃ is undefined.

育児ネタとか、技術ネタとか。

XsvUtility なる Unity ライブラリを作りました

github.com

CSV, TSV を Serialize/Deserialize する Unity 向けライブラリとして XsvUtility を作りました。

概要

XsvUtility は XSV *1 と任意の型とを相互に変換するためのライブラリです。

C# の属性をクラス・構造体のフィールド・プロパティに付与するコトで柔軟性の高い Serialize/Deserialize を実現しています。

何故作ったの?

キッカケとしては、以下のような流れ。

  • 「AssetBundle のサイズ情報を記録したファイルを Amazon S3 にでも置いて管理しようかな。」
  • JSON でも良いんだけど、CSV とか TSV のが楽なんだよなぁ…。」
  • 「でもパーサとか無いんだよなぁ…。」
  • 「作ろう。」
  • 「ついでだから Unity Package Manager で配信できるようにしてみよう。」

思いっきり車輪を再発明している気がしないでも無いですが、まぁ勉強目的ってコトで。

特徴

JsonUtility ライクな使い心地

UnityEngine.JsonUtilityFromJson<T>()ToJson() によって、 Serializable なクラス・構造体の Serializable なフィールドの値を読み書き できるわけですが、 XsvUtilityXSV をパースした結果の行・列を、特殊な C# 属性を付けたフィールド・プロパティに読み書きする 機能を Deserialize<T>()Serialize() というメソッドによって提供します。

リポジトリの README にも書いてありますが、以下のような感じです。

構造の宣言

class Foo
{
    [XsvRow]
    public IEnumerable<Bar> Bars { get; set; } // List<T> などの IEnumerable な Generics 型であれば何でも OK
}

struct Bar
{
    [XsvColumn(0)]
    public string Baz;
    [XsvColumn(1)]
    public int Quz { get; set; }
}

Deserialize/Serialize

var csvText = @"aaa,100
bbb,200";
var foo = Monry.XsvUtility.CsvSerializer.Deserialize<Foo>(csvText);
foo.Bars.ToList()[0].Baz; // aaa
foo.Bars.ToList()[1].Quz; // 200
var foo = new Foo
{
    Bars = new List<Bar>
    {
        new Bar {Baz = "aaa", Quz = 100},
        new Bar {Baz = "bbb", Quz = 200},
    }
};
var tsvText = Monry.XsvUtility.TsvSerializer.Serialize(foo); // aaa,100\nbbb,200

プロパティ・フィールドの両方に対応

Unity のシリアライザは仕様上、 [SerializeField] を付けたフィールドか public なフィールド のみをシリアライズ対象としています。

XsvUtility では、範囲を拡大して [XsvColumn] を付けたフィールドかプロパティ をサポートしています。

アクセス可視性についても、 privateシリアライズ対象としているので、既存のクラス・構造体を汚さないんじゃないかと思っています。

各行をパースした結果を保持するためには [XsvRow] を付けた IEnumerable<T> なフィールド・プロパティ を利用するようにしています。

また、現時点では IEnumerable<T><T> の型に対して [Serializable] なクラス・構造体であることを強制していません
これはいずれ仕様を変える可能性はあります。

特殊な XSV のパースに対応

Microsoft Office などで CSV を出力する際にカンマや改行を含むセルは " で囲まれるという仕様や、ダブルクォーテーションで囲まれているセル内のダブルクォーテーションは "" という風に重ねるという仕様があり、XsvUtility はそれをサポートしています。

詳しくはリポジトリに含めているテストを参照してください。

Unity Package Manager (upm) に対応

まだ完全民主化されていない Unity Package Manager ではありますが、依存を持たないパッケージであれば GitHub の URL を指定出来るようになっています。

ということで、 upm をサポートしてみました。

f:id:monry84:20181230022602p:plain

upm の仕様で、 package.jsonリポジトリルートに置かなければいけないため、 upm 用のリポジトリを別に分けて、開発用のリポジトリから submodule という形で upm 用のリポジトリ を参照させることにしました。*2

まだ author が表示されなかったり、category の使いどころが分からなかったりと、色々ありますが、今後の民主化に期待しましょう。

課題

Documentation, ChangeLog

upm 的にこの辺のルールがあるっぽいので、対応してみる所存です。

なんか、今の時点では Package Manager UI のリンクをクリックしても https://docs.unity3d.com/Packages/tv.monry.xsvutility@0.1/index.html 的な URL に飛ばされてしまうので、どういう形でサポートされるのかは未知数ですが。

パフォーマンス

リフレクションをガッツリ使っていたり、あまり最適化ができていなかったりするので、パフォーマンスはそんなに良くないと思います。

まぁ、そもそも CSV やら TSV やらは構造上最適化が難しい気もするので、あくまでサッと利用する目的ってコトで。

カリカリにチューニングしたぜ!って人からの PullRequest 受付中ですよ!w

*1:CSV, TSV など

*2:この辺改善されてくれると良いなぁ…。