MessagePack-CSharp用の F# 拡張ライブラリを作った
MessagePack-CSharpがリリースされた話を読んですっごーいと感心していたら
F#拡張は @pocketberserker さんが作ってくれるでしょう(チラッ
— neuecc (@neuecc) 2017年3月13日
という通知が飛んできたので即興で作りました。
https://github.com/pocketberserker/MessagePack.FSharpExtensions
拡張でサポートする型
- list
- set
- map
- unit
- option
- 判別共用体
- FSharp.Coreのものはフィールド名ベースの変換のみサポート
- ResultやChoice
- FSharp.Coreのものはフィールド名ベースの変換のみサポート
- Async
- シリアライズで
Async.RunSynchronously
を使っているのでちょっと微妙かも?
- シリアライズで
このあたりに対応させています。
レコードは実は本家のライブラリ側でよしなにやってくれます。 つまり私が実装した拡張を導入しなくても苦労することなく速度の恩恵にあやかれます。
互換
判別共用体に関しては一応程度ですがC#側のUnionと相互変換できます。
- Tagプロパティでケース判定(0, 1, 2…)
- MessagePackObject属性が付いている場合はシーケンシャルなIntKeyを勝手に付与してフィールドをシリアライズ
- 属性が付いていないか、プロパティ名を使う指定になっていればフィールド名を使う
例えばF# 4.1から導入されたResultの具体例Result<int, string>
をstructで表すとこんな感じになるはずです。
[<Union(0, typeof<CsOk>)>] [<Union(1, typeof<CsError>)>] type CsResult = interface end and [<Struct; MessagePackObject(true)>]CsOk(resultValue: int) = member __.ResultValue = resultValue interface CsResult and [<Struct; MessagePackObject(true)>]CsError(errorValue: string) = member __.ErrorValue = errorValue interface CsResult
型パラメータはさすがにどうにもならない気がしています(ほんとか?)
ところで、他の言語で生成されたバイナリを扱ったりその逆パターンを考えるとプロパティ名を小文字にするオプションが欲しい気もするがどうなのでしょう? そういうときにMessagePackを採用することってあまりないから必要ない可能性も高いわけですが、はてさて。
がんばったところ
判別共用体のデシリアライズが(現行の)ZeroFormatter.FSharpExtensionsのものより洗練されています(たぶん)。 MessagePack-CSharpの知見とか、改めてFSharp.CoreのILを眺めた関係でBox化が挟まらなくなったことが大きいですね。
他の部分はそんなに頑張らなかったわけですが、MessagePack-CSharpのAPIがよくできていているので頑張らなくてもなんとかなる、というのが正しいです。
いやほんと素晴らしい、さすがの一言です!
今後
FsPicklerの真似事をするかどうか悩みつつ、要望があれば随時対応かなと考えています。
パフォーマンス調査結果はそのうち掲載します。