Flatbuffers はデータのparse が不要で、非常に読み込み書き込みがはやくて すばらしい。仕事なんかでリアルタイム性の要求が高いゲームサーバでの通信なんかでもつかって。
flatc が生成するコードがつらすぎる。
たとえば以下のような schema で
namespace vfs_schema;
union Index {
File,
Files
}
table File {
id:uint64; // file inode number
name:string;
index_at:int64;
}
table Files {
datas:[File];
}
table Root {
version:int;
index:Index;
}
root_type Root;
こいつらにflatc で生成したcode にgo でアクセスする場合.
vRoot := vfs_schema.GetRootAsRoot(buf, 0)
uTable := new(flatbuffers.Table)
vRoot.Index(uTable)
fbsFile := new(vfs_schema.File)
fbsFile.Init(uTable.Bytes, uTable.Pos)
fbsFile.Id()
fbsFile.Name()
fbsFile.IndexAt()
Flatbuffers のつらい点
まぁflatc でやるとき問題はいくつかってあって, 主に以下のような感じ
- flatc で生成したコードを利用したコードを後でみてもまったくわからない(全部調べ直し)
- streaming で流した場合にコンテンツのサイズがわからない。
- データの部分的な書き換えが固定長のデータの部分だけで、可変長のものはできない。
- データの作成の歳 []byte の領域で後ろから書いていって、そこからだんだん前につめていくのでmemcpy とかが走りまくり。
さすがにこれではつらすぎる。効率が悪いので
fbs-query というものをつくった。
Rust 方面でもやはりflatc コードが糞なのに耐えきれず自分でparser/generater つくってる人はいるぽい
fbs-query をつくってみた。
最終的には1-4を全部解決する予定ですが、まだ 3,4 あたりはこれから解決していく予定
上のようなアクセスコードは以下のような感じで。 これできっと忘れない。
//io io.Reader
q := query.Open(io)
q.Len()
q.Index().File().Id()
q.Index().File().Name()
q.Index().File().IndexAt()
streaming できた場合とかは Next() を使うと次のメッセージがあつかえる
q := query.Open(io)
n := q.Next()
n.Index().File().Name()
Flatbuffers 的にいうVector データ(slice?) もイテレータ的にアクセスできるようにした。
fbs := query.Open(ioReader)
fbs.Files().First()
fbs.Files().Last()
fbs.Files().Len()
fbs.Files().At(1)
fbs.Files().All()
fbs.Files().Select(func(m query.FbsFile) bool {
return m.Id() == 10
})
// for streaming data
fbs.Next().Files().First()
Marshal はまだだが Unmarshal はできる
f := struct{
ID uint64 `fbs:"Id"`
Name []byte `fbs:"Name"`
IndexAt int64 `fbs:"IndexAt"`
}{}
fbs := query.OpenByBuf(buf)
fbs.Files().First().Unmarshal(&f)
書き込みとかMarshal とかはこれから…