MessagePackの新しいRust実装、messagepack-rsをリリースしました
2019/08/05
もともとは独自のシリアライズフォーマットを作る予定だった
正確に言うと予定だった
ではなく既に仕様も決まりRustでの実装も完了していた。
なんでMessagePackなどの既存のものではなく新しいフォーマットを作ったかと言うと、いくつか理由があってだいたいこんな感じ↓
新しいフォーマットを作った理由
- MessagePackの仕様上Map型のkeyにはどんな型の値でも入れられるようになっているのだけど、Rustの場合HashMapやBTreeMapのkeyにf32やf64のような浮動小数点数型を入れられないという問題がある(MessagePackのRustの実装の一つであるRMPはMap型をVec<(Value, Value)>で実装するという力技をやっている)
- MessagePackはストリーム処理ができないと思っていた(完全に見落としていただけでちゃんとストリーム処理できる)
- Extension型を作る場合必ず1バイト分オーバーヘッドができてしまう(その型がExtension型であることを示すための1バイト)
- BigInt型、BigDecimal型、Date型などが定義されていない
これらの理由から独自のフォーマットとその実装を作ったのだけど、完成したあたりでふと↓のような解決策?(特にMapのやつ)に気がついてしまい、新しくフォーマット作ったらドキュメント作ったりとか、言語ごとにライブラリ作らないといけないし、既存のMessagePackを使ったほうがよいのでは?と思い、独自フォーマットを泣く泣く捨てる形になった。
気がついてしまった解決策(?)
- Mapのキーに文字列しか入れられないようにする
- Extension型の1バイト分のオーバーヘッドはMessagePackの他のサイズ削減機能(fixXXX系のヘッダー部分にデータを入れられる機能)で多くの場合相殺できる
- BigInt型、BigDecimal型、Date型はExtension型として自分で定義すれば使える(個人的にこれらの型は標準で対応してもらえると嬉しい…)
MessagePackの新しいRust実装を作ることに
既存のRust実装であるRMPは軽く見た感じ3つの問題があるように感じた。
- 上の方で書いたようにMap型をVec<(Value, Value)>で実装している(MessagePackの仕様をちゃんと守っているとも言える)
- Timestamp型に対応しておらず、2019年8月現在、型情報に負の値を入れられない(Timestamp型の型番号は-1)ため自分でTimestamp型を実装することもできず、それに対するissueも1年近く放置されている
- ストリームに対応していない(多分…使い方わかってないだけで実は対応していたらすみません…)
これらの問題がない実装が個人的に必要だったので新しくmessagepack-rsを作成した。
messagepack-rsの特徴
- Map型をBTreeMap<String, Value>で実装(HashMapではなくBTreeMapな理由は文字列として出力したときにHashMapだと順番がぐちゃぐちゃになってしまい見にくいため)
- Timestamp型に対応
- ストリームに対応
messagepack-rsの使い方
基本的な使い方
ストリーム
Extension(定義が簡単で使うときにちょっと面倒くさい方法)
Extension(定義が少し面倒だけど使うときに楽な方法)
だいたいこんな感じで使える。
まだSerdeに対応してないのでExtensionの定義が面倒だけどそのうち対応予定。
僕と同じような理由でRMPが利用できない場合、試しに使ってみてもらえたら嬉しいです🤗