はじめに
前に簡易的なunmarshalerかいたので それに機能追加した話
この時点では、対応するtypeはVarintとLength-delimitedだけだったので、固定長64bit/32bitフィールドをパースできるようにしました。
差分は以下 https://github.com/convto/protowire/compare/6f4b6c1..eb618a7
対応
とくに難しいことはしていない。
単に固定長フィールドをサポートしつつ、適切な型でbindしてるだけですね。
差分をみればわかるんですが、このあたりのbyte読み取りや型変換は標準パッケージに実装されているので、何も考えずに実装できて楽でした。たとえば以下
binary.LittleEndian.Uint64()
およびその32bit実装math.Float64frombits()
およびその32bit実装
ひとつ、最初間違って実装してしまったのは sfixed64/32
のときにzigzagで読み取ろうとしたこと。
固定長byte列の場合は最初から64/32bitなりで全サイズのデータがバイナリに含まれるので、可変長のときのように負数ならzigzagを使ったほうがお得!とならない。
(2の補数表現だろうが、値が 1
だろうが -1
だろうが、どっちみち固定長ぶんバイトが使われるため)
そのためsfixed64/32のときはzigzagを使わないようで、いままでの流れでzigzagつかうunmarshalerを実装したらおかしな値が出力されてerrorになった。
あとはいつもの通り https://github.com/golang/protobuf で生成したバイナリを読み取ってみてテストした。
感想
めちゃめちゃ簡単だった。これであとは下位互換をのぞくとrepeatableの対応とか別メッセージの埋め込み対応とかだけかな?あとちょっとでひとしきり実装できそう。
テストがちょっとめんどくさい。手元でいちいちバイナリ吐いて〜とするのが面倒なので、testdirとかつくってそこにテスト用のproto定義とprotoc-gen-goで生成したコード配置してテストではそれを参照するようにしたほうが楽かなぁ。
かなり素朴に実装していてベタッと書いてるので、ひととおり仕様準拠したらリファクタしてもいいかも