銀月の符号

Python 使い見習いの日記・雑記

MessagePack メモ

Python

help(msgpack) するとファイルライクオブジェクトに対して入出力する pack, unpack と、 Python 文字列を対象とする packb (= packs), unpackb (= unpacks) の説明あり。

import sys
import msgpack

msgpack.pack([1, True, 'example'], sys.stdout)
import sys
import msgpack

print msgpack.unpack(sys.stdin)
$ python write.py | python read.py
[1, True, 'example']

しかしコードを斜め読みすると Packer, Unpacker というのもあった。こちらのほうが本命で pack, unpack はショートカット用かな。

import sys
import msgpack

packer = msgpack.Packer()
sys.stdout.write(packer.pack([1, True, 'example']))
sys.stdout.write(packer.pack('spam'))
sys.stdout.write(packer.pack(range(5)))
sys.stdout.write(packer.pack({'a': 'b', 'c': 'd'}))
import sys
import msgpack

unpacker = msgpack.Unpacker()
while True:
    buf = sys.stdin.read()
    if not buf:
        break
    unpacker.feed(buf)
    for obj in unpacker:
        print obj
$ python write2.py | python read2.py
[1, True, 'example']
spam
[0, 1, 2, 3, 4]
{'a': 'b', 'c': 'd'}

Ruby

http://msgpack.sourceforge.net/ruby:snippets 。明日試してみる。 http://d.hatena.ne.jp/viver/20100324/p1 も読む。 Copy-on-Write によるゼロ・コピーデシリアライズ対応。

C

シリアライズhttp://msgpack.sourceforge.net/c:snippets のまま。

#include <msgpack.h>
#include <stdio.h>

int main(void) {
    msgpack_sbuffer sbuf;
    msgpack_packer pk;
    
    msgpack_sbuffer_init(&sbuf);
    msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write);
    
    msgpack_pack_array(&pk, 3);
    msgpack_pack_int(&pk, 1);
    msgpack_pack_true(&pk);
    msgpack_pack_raw(&pk, 7);
    msgpack_pack_raw_body(&pk, "example", 7);
        
    fwrite(sbuf.data, sbuf.size, 1, stdout);
        
    msgpack_sbuffer_destroy(&sbuf);
            
    return 0;
} 

シリアライズhttp://msgpack.sourceforge.net/c:snippets の改悪。 Advanced streaming deserialization も読む必要がありそうだがこれは明日に。

#include <msgpack.h>
#include <stdio.h>

int main(void) {
    msgpack_zone *mempool;
    msgpack_object obj;
    msgpack_unpack_return ret;
    size_t offset = 0;
    char buf[8192];
    size_t size;

    size = fread(buf, 1, 8192, stdin);

    while (1) {
        mempool = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE);
        ret = msgpack_unpack(buf, size, &offset, mempool, &obj);
        switch(ret) {
        case MSGPACK_UNPACK_SUCCESS:
            printf("a object is unpacked and no buffer remain: ");
            msgpack_object_print(stdout, obj);
            printf("\n");
            msgpack_zone_free(mempool);
            return 0;
        case MSGPACK_UNPACK_EXTRA_BYTES:
            printf("a object is unpacked: ");
            msgpack_object_print(stdout, obj);
            printf("\n");
            msgpack_zone_free(mempool);
            break;
        case MSGPACK_UNPACK_CONTINUE:
            printf("buffer is to insufficient to unpack a object\n");
            return 1;
        case MSGPACK_UNPACK_PARSE_ERROR:
            printf("parse error\n");
            return 1;
        }
    }
}
$ ./write | ./read
a object is unpacked and no buffer remain: [1, true, "example"]

えっと、 msgpack_unpack の戻り値 MSGPACK_UNPACK_SUCCESS はぴったり読みきったことを示し MSGPACK_UNPACK_EXTRA_BYTES はまだデータが余っていることを示すのか。これは Python 版の Unpacker 同様、複数オブジェクトを詰め込んだファイルを綺麗に処理できる予感。 試してみる。

$ python write2.py | ./read
a object is unpacked: [1, true, "example"]
a object is unpacked: "spam"
a object is unpacked: [0, 1, 2, 3, 4]
a object is unpacked and no buffer remain: {"a"=>"b", "c"=>"d"}

うん、読めた。

C++

http://msgpack.sourceforge.net/cpp:snippets 。明日試してみる。