#macro-derive #traits #prost #message #protobuf #automatic #helper

nightly autoproto

用于替换 prost::Message 特性的 derive 宏,并提供支持特性类型以简化此特性实现

3 个版本

0.1.2 2021 年 8 月 27 日
0.1.1 2021 年 8 月 17 日
0.1.0 2021 年 8 月 11 日

#933Rust 模式

Unlicense

70KB
2K SLoC

Autoproto

此 crate 实现了对 prost::Message 特性的自定义 derive 宏,同时包含一些辅助特性以尽可能简化自动推导 - 基本上是将更多信息放入类型系统中而不是宏实现中。如果宏没有执行您需要的操作,您可以实现“基础特性”之一,如 ProtoStructProtoOneof,并使用 generic 模块中的函数来实现其余特性。

限制

(目前) 不支持嵌套在结构体中的 oneof

这最终可以解决,但现在是此 derive 宏的一个主要限制,因为我们不能支持像这样使用 protobuf 类型

message Foo {
    string first = 1;
    oneof some_oneof {
        string second = 2;
        string third = 3;
    }
}

由于库的当前编写方式,它仅支持当它是消息的唯一成员时的 oneof

不支持从 .proto 文件自动生成

这是与 prost 最大的不同之处,这是一个有意的选择。我认为从 protobuf 文件自动生成 Rust 文件(至少部分)是 prost 的一个错误特性,因为这在许多情况下会导致 Rust 中出现极其难以管理的类型。Rust 具有深层次且丰富的类型系统,而 Protobuf 无法很好地表示它。最终我希望有编译时检查,以检查 Rust 类型是否与给定的 protobuf 文件兼容,但目前尚未实现。

#[derive(prost::Message)] 的改进和变更

支持更多类型作为字段

此宏支持除了 Vec 以外的集合用于重复字段,结构体中的裸枚举,usize/isize,以及映射。对于重复的集合,任何实现了 std::iter::Extend 并且可以迭代该类型的引用的类型都可以作为结构体中的集合使用。目前,您必须手动实现 ProtoProtoEncode,但如果有朝一日 feature(specialization) 被稳定化,这种限制应该会得到缓解。

虽然目前我们无法自动支持实现 proto::Message 的任何类型作为字段 - 因为这个特质是为标量实现的,而我们有自己的特质的主要原因是我们可以为标量提供不同的实现 - 您只需实现 IsMessage 标记特质,以便允许该类型作为 #[derive)] 类型的字段使用。

此外,消息不再需要被包装在 Option 中,因为 protobuf 的急切解码已经要求所有消息实现 Default。如果您想区分字段是否提供默认值或根本不提供,则可以将任何类型包装在 Option 中。

更多类型的推导

此宏允许对几乎任何标记联合体进行推导,并允许对泛型结构进行推导。例如

# #![feature(generic_associated_types)]
#[derive(Copy, Clone, PartialEq, Debug, autoproto::Message)]
enum Oneof<A, B, C> {
    Nothing,
    One(A),
    Two(A, B),
    Three(A, B, C),
}

不允许混合标记-非标记结构体

prost 宏的一个变化是,要么所有字段都必须是标记的,要么不能有标记的字段。例如,以下两个是可以的

# #![feature(generic_associated_types)]
#[derive(Copy, Clone, PartialEq, Default, Debug, autoproto::Message)]
struct SomeStructTagged<A, B, C, D, E> {
    #[autoproto(tag = 1)]
    a: A,
    #[autoproto(tag = 2)]
    b: B,
    #[autoproto(tag = 3)]
    c: C,
    #[autoproto(tag = 4)]
    d: D,
    #[autoproto(tag = 5)]
    e: E,
}
#[derive(Copy, Clone, PartialEq, Default, Debug, autoproto::Message)]
struct SomeStruct<A, B, C, D, E> {
    a: A,
    b: B,
    c: C,
    d: D,
    e: E,
}

但是以下这个是不可以的

# #![feature(generic_associated_types)]
#[derive(Copy, Clone, PartialEq, Default, Debug, autoproto::Message)]
struct SomeStruct<A, B, C, D, E> {
    a: A,
    b: B,
    #[autoproto(tag = 1)]
    c: C,
    d: D,
    e: E,
}

依赖关系

~2MB
~46K SLoC