7 个版本 (4 个重大变更)
0.5.0 | 2022 年 9 月 15 日 |
---|---|
0.4.0 | 2020 年 3 月 27 日 |
0.3.0 | 2019 年 12 月 12 日 |
0.2.1 | 2019 年 12 月 4 日 |
0.1.0 | 2019 年 2 月 14 日 |
#1707 in 过程宏
每月下载量 250
在 15 个 Crates 中使用 (通过 exonum-proto)
30KB
483 行
protobuf-convert
方便将 Rust 数据结构序列化为 Protocol Buffers 的宏。
简介
这是从 exonum-derive 分支出来的,进行了一些修改以简化与其他项目的集成,并添加了一些新功能。
使用方法
首先,在 Cargo.toml
中添加依赖项
protobuf-convert = "0.4.0"
然后,定义一个 ProtobufConvert
特征
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>;
}
要使用它,请导入特征和宏
例如,给定以下 protobuf
message Ping {
fixed64 nonce = 1;
}
rust-protobuf 将生成以下结构体
#[derive(PartialEq,Clone,Default)]
pub struct Ping {
// message fields
pub nonce: u64,
// special fields
pub special_fields: ::protobuf::SpecialFields,
}
我们可能希望将该结构体转换为更符合 Rust 习惯的形式,并派生更多特征。以下是必要的代码
// Import trait
use crate::proto::ProtobufConvert;
// Import macro
use protobuf_convert::ProtobufConvert;
// Import module autogenerated by protocol buffers
use crate::proto::schema;
#[derive(ProtobufConvert)]
#[protobuf_convert(source = "schema::Ping")]
struct Ping {
nonce: u64,
}
请注意,必须为所有字段实现 ProtobufConvert
特征,请参阅 u64
的示例实现
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)
}
}
现在,在 Ping
和 schema::Ping
之间进行转换可以轻松完成。
Enum
支持
一个更复杂的示例,包含枚举
message Ping {
fixed64 nonce = 1;
}
message Pong {
fixed64 nonce = 1;
}
message Message {
oneof kind {
Ping Ping = 1;
Pong Pong = 2;
}
}
#[derive(ProtobufConvert)]
#[protobuf_convert(source = "schema::Ping")]
struct Ping {
nonce: u64,
}
#[derive(ProtobufConvert)]
#[protobuf_convert(source = "schema::Pong")]
struct Pong {
nonce: u64,
}
#[derive(ProtobufConvert)]
#[protobuf_convert(source = "schema::Message")]
enum Message {
Ping(Ping),
Pong(Pong),
}
它就这样工作了!
您还可以为枚举变体生成 From
和 TryFrom
特征。请注意,如果枚举变体具有相同的字段类型,则此功能将不起作用。要使用此功能,请添加 impl_from_trait
属性。
#[derive(ProtobufConvert)]
#[protobuf_convert(source = "schema::Message"), impl_from_trait]
enum Message {
Ping(Ping),
Pong(Pong),
}
From<Ping>
、From<Pong>
以及TryFrom<..>
特征将被生成。
与枚举一起使用的另一个属性是rename
。它指示宏在属性参数中生成指定case的方法。
#[derive(ProtobufConvert)]
#[protobuf_convert(source = "schema::Message"), rename(case = "snake_case")]
enum Message {
Ping(Ping),
Pong(Pong),
}
目前,仅支持蛇形命名。
跳过字段
此宏还支持在struct
中跳过字段,这样在序列化时将被忽略,即它们不会被映射到模式中的任何字段。
#[derive(ProtobufConvert)]
#[protobuf_convert(source = "schema::Ping")]
struct Ping {
pub nonce: u64,
#[protobuf_convert(skip)]
my_private_field: u64
}
请注意,您只能跳过实现Default
特质的字段。
覆盖转换规则
此宏还支持类似serde的属性with
,用于具有自定义from_pb
和to_pb
转换实现的模块。
protobuf-convert
将使用函数$module::from_pb
和$module::to_pb
代替ProtobufConvert
特质为指定的字段。
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum CustomId {
First = 5,
Second = 15,
Third = 35,
}
#[derive(Debug, Clone, ProtobufConvert, Eq, PartialEq)]
#[protobuf_convert(source = "proto::SimpleMessage")]
struct CustomMessage {
#[protobuf_convert(with = "custom_id_pb_convert")]
id: Option<CustomId>,
name: String,
}
mod custom_id_pb_convert {
use super::*;
pub(super) fn from_pb(pb: u32) -> Result<Option<CustomId>, anyhow::Error> {
match pb {
0 => Ok(None),
5 => Ok(Some(CustomId::First)),
15 => Ok(Some(CustomId::Second)),
35 => Ok(Some(CustomId::Third)),
other => Err(anyhow::anyhow!("Unknown enum discriminant: {}", other)),
}
}
pub(super) fn to_pb(v: &Option<CustomId>) -> u32 {
match v {
Some(id) => *id as u32,
None => 0,
}
}
}
另请参阅
依赖项
~0.8–3MB
~54K SLoC