ここ三回くらいprotobufの記事を書いてきましたが、Goばかりだったので、Rustで読み込んでみました。
事前準備:Goでバイナリを出力する
user.protoを以下のように定義します。
syntax = "proto3"; package user; message User { string name = 1; int32 age = 2; }
Go用にprotocする
❯ protoc -I=./ --go_out=./ user.proto
user.pb.goが生成されます。
バイナリを書き出す
以下のユーザをprotobufのバイナリとしてgo_user.binを書き出します。
| フィールド | 値 |
|---|---|
| Name | Alice |
| Age | 20 |
出力用のコードは以下の通りです。
package main import ( "fmt" "io/ioutil" "log" pb "github.com/cipepser/protobuf-sample/rust-protobuf-example/user" "github.com/golang/protobuf/proto" ) func main() { p := &pb.User{ Name: "Alice", Age: 20, } out, err := proto.Marshal(p) if err != nil { log.Fatal(err) } fmt.Println(out) if err := ioutil.WriteFile("./go_user.bin", out, 0644); err != nil { log.Fatalln("Failed to write:", err) } }
Rustで読み込む
いよいよ本題のRustです。
Cargo.tomlの設定
Rustでprotobufを扱うためにrust-protobufを使います。
Cargo.tomlのdependenciesにprotobufを記載します。
READMEにも書いてありますが、bytesクレートを使っているのでbytesも記載します。
[dependencies]
protobuf = { version = "~2.0", features = ["with-bytes"] }
2019/08/03追記
stepancheg/rust-protobuf: Rust implementation of Google protocol buffersに、version2未満がサポート対象外になったと書いてあるので、追記現在では以下のように記載します。
[dependencies]
protobuf = { version = "2", features = ["with-bytes"] }
Rust用にprotocする
user.protoは、Goでprotocしたときと同じものです。
❯ protoc --rust_out src/ user.proto
以下のようなメッセージが出る場合は、protoc-gen-rustがないのでインストールしましょう。
protoc-gen-rust: program not found or is not executable --rust_out: protoc-gen-rust: Plugin failed with status code 1
以下でインストール出来ます(Cargo.tomlに書いてもいいのかも)。
❯ cargo install protobuf-codegen
protocがうまくいけば、src/user.rsがgenerateされます。
読み込む
ファイル読み込み、User型にmerge、標準出力するまでのコードは以下のとおりです。
extern crate protobuf; mod user; use user::User; use std::fs::File; use std::io::{BufReader}; use protobuf::{CodedInputStream, Message}; fn main() { let file = File::open("./go_user.bin").expect("fail to open file"); let mut buffered_reader = BufReader::new(file); let mut cis = CodedInputStream::from_buffered_reader(&mut buffered_reader); let mut u = User::new(); u.merge_from(&mut cis).expect("fail to merge"); println!("Name: {}", u.get_name()); println!("Age: {}", u.get_age()); }
実行すると、以下のようにNameとAgeが読み取れていることがわかります。
/usr/local/bin/cargo run --color=always --package rust-protobuf-example --bin rust-protobuf-example Finished dev [unoptimized + debuginfo] target(s) in 0.04s Running `target/debug/rust-protobuf-example` Name: Alice Age: 20 Process finished with exit code 0