園児ニア日記

MessagePackの新しいRust実装、messagepack-rsをリリースしました

もともとは独自のシリアライズフォーマットを作る予定だった

正確に言うと予定だったではなく既に仕様も決まりRustでの実装も完了していた。
なんでMessagePackなどの既存のものではなく新しいフォーマットを作ったかと言うと、いくつか理由があってだいたいこんな感じ↓

新しいフォーマットを作った理由

  1. MessagePackの仕様上Map型のkeyにはどんな型の値でも入れられるようになっているのだけど、Rustの場合HashMapやBTreeMapのkeyにf32やf64のような浮動小数点数型を入れられないという問題がある(MessagePackのRustの実装の一つであるRMPはMap型をVec<(Value, Value)>で実装するという力技をやっている)
  2. MessagePackはストリーム処理ができないと思っていた(完全に見落としていただけでちゃんとストリーム処理できる)
  3. Extension型を作る場合必ず1バイト分オーバーヘッドができてしまう(その型がExtension型であることを示すための1バイト)
  4. BigInt型、BigDecimal型、Date型などが定義されていない

これらの理由から独自のフォーマットとその実装を作ったのだけど、完成したあたりでふと↓のような解決策?(特にMapのやつ)に気がついてしまい、新しくフォーマット作ったらドキュメント作ったりとか、言語ごとにライブラリ作らないといけないし、既存のMessagePackを使ったほうがよいのでは?と思い、独自フォーマットを泣く泣く捨てる形になった。

気がついてしまった解決策(?)

  1. Mapのキーに文字列しか入れられないようにする
  2. Extension型の1バイト分のオーバーヘッドはMessagePackの他のサイズ削減機能(fixXXX系のヘッダー部分にデータを入れられる機能)で多くの場合相殺できる
  3. BigInt型、BigDecimal型、Date型はExtension型として自分で定義すれば使える(個人的にこれらの型は標準で対応してもらえると嬉しい…)

MessagePackの新しいRust実装を作ることに

既存のRust実装であるRMPは軽く見た感じ3つの問題があるように感じた。

  1. 上の方で書いたようにMap型をVec<(Value, Value)>で実装している(MessagePackの仕様をちゃんと守っているとも言える)
  2. Timestamp型に対応しておらず、2019年8月現在、型情報に負の値を入れられない(Timestamp型の型番号は-1)ため自分でTimestamp型を実装することもできず、それに対するissueも1年近く放置されている
  3. ストリームに対応していない(多分…使い方わかってないだけで実は対応していたらすみません…)

これらの問題がない実装が個人的に必要だったので新しくmessagepack-rsを作成した。

messagepack-rsの特徴

  1. Map型をBTreeMap<String, Value>で実装(HashMapではなくBTreeMapな理由は文字列として出力したときにHashMapだと順番がぐちゃぐちゃになってしまい見にくいため)
  2. Timestamp型に対応
  3. ストリームに対応

messagepack-rsの使い方

基本的な使い方

ストリーム

Extension(定義が簡単で使うときにちょっと面倒くさい方法)

Extension(定義が少し面倒だけど使うときに楽な方法)

だいたいこんな感じで使える。
まだSerdeに対応してないのでExtensionの定義が面倒だけどそのうち対応予定。
僕と同じような理由でRMPが利用できない場合、試しに使ってみてもらえたら嬉しいです🤗