ここ三回くらい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