Macros for convenient serialization of Rust data structures into/from Protocol Buffers.
This is a fork of exonum-derive with some changes to allow easier integration with other projects, and some new features.
First, add the dependency in Cargo.toml
:
protobuf-convert = "0.1.0"
Then, define a ProtobufConvert
trait:
```rust trait ProtobufConvert { /// Type of the protobuf clone of Self type ProtoStruct;
/// Struct -> ProtoStruct
fn to_pb(&self) -> Self::ProtoStruct;
/// ProtoStruct -> Struct
fn from_pb(pb: Self::ProtoStruct) -> Result<Self, Error>;
} ```
And to use it, import the trait and the macro:
For example, given the following protobuf:
protobuf
message Ping {
fixed64 nonce = 1;
}
rust-protobuf will generate the following struct:
```rust
pub struct Ping { // message fields pub nonce: u64, // special fields #[cfgattr(feature = "with-serde", serde(skip))] pub unknownfields: ::protobuf::UnknownFields, #[cfgattr(feature = "with-serde", serde(skip))] pub cachedsize: ::protobuf::CachedSize, } ```
We may want to convert that struct into a more idiomatic one, and derive more traits. This is the necessary code:
```rust // Import trait use crate::proto::ProtobufConvert; // Import macro use protobuf_convert::ProtobufConvert; // Import module autogenerated by protocol buffers use crate::proto::schema;
struct Ping { nonce: u64, } ```
Note that the ProtobufConvert
trait must be implemented for all the fields,
see an example implementation for u64
:
rust
impl ProtobufConvert for u64 {
type ProtoStruct = u64;
fn to_pb(&self) -> Self::ProtoStruct {
*self
}
fn from_pb(pb: Self::ProtoStruct) -> Result<Self, Error> {
Ok(pb)
}
}
Now, converting between Ping
and schema::Ping
can be done effortlessly.
A more complex example, featuring enums:
protobuf
message Ping {
fixed64 nonce = 1;
}
message Pong {
fixed64 nonce = 1;
}
message Message {
oneof kind {
Ping Ping = 1;
Pong Pong = 2;
}
}
```rust
struct Ping { nonce: u64, }
struct Pong { nonce: u64, }
enum Message { Ping(Ping), Pong(Pong), } ```
And it just works!