scodecでmsgpackライブラリを作ってみた

pocketberserker/scodec-msgpack · GitHub

名前は特に思いつかなかったのでそのまんまです。

実装理由

  • scalazフレンドリーなmsgpackライブラリがほしかった(建前)
  • scodecの勉強のため
  • そろそろ一度はscalaのライブラリレベルのコード書かないとなーと思っていた(本音)

必要なもの

scodecに依存しているので、scodecに関連する知識が必要です。具体的には、

  • scodec-bits
  • scalazの一部(少なくともEither)
  • shaplessの一部(HListの使い方は必須。Genericも知っていると便利?)

とかです。

まぁ、Eitherは難しくないですしshapelessもHListを使うことに限れば理解するのに何日もかからないと思うので、そんなにこわくないはずです。

使い方

極力scodecと同じように書けるようにしたつもりです。

import scodec._

case class Point(x: Int, y: Int, z: Int)
val pointCodec = (msgpack.int :: msgpack.int :: msgpack.int).as[Point]

val encoded: String \/ BitVector = pointCodec.encode(Point(-5, 1024, 1))
// \/-(BitVector(40 bits, 0xfbcd040001))

val decoded: String \/ Point = pointCodec.decode(BitVector(0xfb, 0xcd, 0x04, 0x00, 0x01))
// \/-(Point(-5,1024,1))

pointCodecの中身がint8ではなくmsgpack.intなのが重要な点です。

考えないといけないこと

  • extを楽に生成することができない
  • 無駄にimplicitを使ってしまっている気がするので外す
  • Map周りがこれでいいのかわからない
  • IndexedSeqをVectorに差し替えるかも
  • case classからjson styleにマッピングする関数を作るかどうか
  • パフォーマンス調査

実装時に困ったこと

scodecを調べながらだったので結構時間がかかってしまいました。 README、テストコード、ブログ、最終的にソースコードと読んでいったのでこの作業で2,3日使ったような…?

なお、CodecがMonadでないことはねこはるさんとxuwei-kさんに教えていただきました。ありがとうございました。

あとはScalaの作法がわからず困ったとか、そんな感じです。

おわりに

scodecのコードはわりと読みやすいと思います(Argonautに比べて、ですが)。 その影響で解説記事を書く気力がおきない…ので、情報がほしい方は私に「記事の進捗どうですか」と連呼してください。