Protocol Buffersは、Google 社が開発している直列化のための公開技術であり、nine の直列化に利用することができる。
nine では、C++ 生成コードのみの対応となっている。
ここでは protobuf を用いて定義、生成したデータを nine から使う方法について説明する。 Protocol Buffers そのもの利用方法については、Protocol Buffers 翻訳文書を参照のこと。
protobuf で定義したメッセージには、対応する C++ クラスが定義される。 これをそのままデータ型として扱う。 たとえばメッセージクラスのメンバ変数にすることができる。
protobuf から生成したクラスは、nine とは無関係の C++ クラスでしかない。 これをMessage クラスの直書き方法に則って、nine のメッセージでラップする。 google::protobuf::Message を nine::Buffer へ読み書きする関数を提供しているので、これを使えばよい。
foo.proto:
message Foo {
required int32 id = 1;
};
bar.cpp:
#include <foo.pb.h>
#include <nine/ninepb.h>
class Bar: public nine::Message {
Foo m_foo;
public:
virtual int getMarshalSize() const
{ return nine::PbGetMarshalSize(&m_foo); }
virtual void marshal(Buffer* pBuf) const
{ nine::PbMarshal(pBuf, &m_foo); }
virtual void unmarshal(Buffer* pBuf)
{ nine::PbUnmarshal(pBuf, &m_foo); }
};
protobuf から生成されたメッセージクラスと nine::Message を多重継承した新たなクラスを定義するやり方である。
protobuf メッセージの操作インターフェースをそのまま使うことができ、さらに nine::Message としても扱うことができる。
nineメッセージでは、メッセージID のユニークさをユーザーが担保する必要がある。 しかし、protobuf ではメッセージID というものは無いので、特別な決まり事を導入した。
foo.proto:
message Foo {
enum En { NINE_MSGKIND = 2; NINE_MSGTYPE = 0x011; }
require int32 id = 1;
...
}
KIND, TYPE の意味は nineメッセージのそれと同じである。
foouser.cpp:
#include <foo.pb.h>
#include <nine/ninepb.h>
class MyServer: public nine::MessageServer {
typedef nine::PbMessage< Foo > PbFoo;
void handleFoo(Pbfoo* pMsg) { ... }
bool handleMessage(nine::Message* pMsg) {
if (tryDispatch(&MyServer::handleFoo, pMsg)) { return true; }
else { ... }
}