Haskell binding for MessagePack

MessagePack の Haskell binding を作りました。

MessagePackとは

http://msgpack.sourceforge.jp/
id:viver さんが開発された高速なバイナリシリアライザです。
http://d.hatena.ne.jp/viver/20080816/p1http://d.hatena.ne.jp/nobu-q/20091209 が詳しいです。

インストール方法

githubにレポジトリを置いています。http://github.com/tanakh/hsmsgpack にあります。
パッケージをHackageにアップロードしています。http://hackage.haskell.org/package/msgpack-0.1.0 にて公開されています。

インストールは、MessagePackをインストールしてから、

$ cabal install msgpack

で行えます。

使い方

http://fxp.hp.infoseek.co.jp/doc/msgpack/
ここにhaddockドキュメントがあります(Hackageでのビルドがこけているため、Hackageにドキュメントが生成されていないので、暫定的にここに置いています。将来的には移動する可能性が高いです)。

Low Levelなインターフェースとして、MessagePackのC APIがほぼすべて一対一対応の関数が Data.MessagePack.Base にありますので、これを使えばだいたい何でもできるはずです。 http://msgpack.sourceforge.jp/c:doc.ja こちらが参考になるはずです。

import Control.Monad
import Data.MessagePack

main = do
  sb <- newSimpleBuffer -- Packerが使うバッファ作成
  pc <- newPacker sb -- Packer作成
  
  packArray  pc 3     -- 三要素の配列をパックしますよ
  packS32    pc 12345 -- 整数
  packDouble pc 3.14  -- 浮動小数
  packTrue   pc       -- Bool
  
  bs <- simpleBufferData sb -- バッファにたまったデータを取り出す

  print bs -- > "\147\205\&09\203@\t\RS\184Q\235\133\US\195"
  
  up <- newUnpacker defaultInitialBufferSize -- Unpacker作成
  unpackerFeed up bs -- Unpackerにデータを食わせる
  
  resp <- unpackerExecute up -- デシリアライズ実行
  guard $ resp==1 -- 成功すると1が返る
  obj <- unpackerData up -- デシリアライズされたデータを取り出す
  
  print obj -- > ObjectArray [ObjectInteger 12345,ObjectDouble 3.14,ObjectBool True]

Low Levelなインターフェースの上に、High Levelなインターフェースを作っています。今のところ、汎用的なpack関数と、単一のpack, unpackを簡単に行う関数があります。

main = do
  sb <- newSimpleBuffer
  pc <- newPacker sb
  
  -- OBJECTクラスの値を適当にpackする
  pack pc [(1, 2), (3, 4), (5::Int, 6::Int)]

  ...
main = do
  bs <- packb [1,2,3::Int] -- お手軽pack
  Right dat <- unpackb bs  -- お手軽unpack
  print (dat :: [Int]) -- > [1,2,3]
main = do
  let bs = packb' [1,2,3::Int] -- pure版
  let Right dat = unpackb' bs -- pure版
  print (dat :: [Int]) -- > [1,2,3]

ObjectとHaskellのデータの相互変換は toObject、 fromObject で行えます。

main = do
  bs <- packb [1,2,3::Int]
  Right (_, obj) <- withZone $ \z -> unpackObject z bs
  let Right dat = fromObject obj
  print (dat :: [Int])