rust-protobuf icon indicating copy to clipboard operation
rust-protobuf copied to clipboard

Customized generation for well-known types

Open neilisaac opened this issue 2 years ago • 3 comments

Is it possible to generate protobuf stubs using my own generated well-known types instead of the pre-generated ones in the protobuf crate?

message ExampleMessageWithWellKnownTypes {
    google.protobuf.Duration duration = 1;
    google.protobuf.Timestamp timestamp = 2;
    google.protobuf.Struct struct = 3;
}

with customization

impl CustomizeCallback for SerdeSerializeDeserialize {
    fn message(&self, _message: &MessageDescriptor) -> Customize {
        Customize::default().before("#[derive(::serde::Serialize, ::serde::Deserialize)]")
    }
...

generates

#[derive(PartialEq,Clone,Default,Debug)]
#[derive(::serde::Serialize, ::serde::Deserialize)]
// @@protoc_insertion_point(message:x.proto.ExampleMessageWithWellKnownTypes)
pub struct ExampleMessageWithWellKnownTypes {
    // message fields
    #[serde(with="::protobuf_serde_helpers::MessageFieldDef")]
    // @@protoc_insertion_point(field:x.proto.ExampleMessageWithWellKnownTypes.duration)
    pub duration: ::protobuf::MessageField<::protobuf::well_known_types::duration::Duration>,
    #[serde(with="::protobuf_serde_helpers::MessageFieldDef")]
    // @@protoc_insertion_point(field:x.proto.ExampleMessageWithWellKnownTypes.timestamp)
    pub timestamp: ::protobuf::MessageField<::protobuf::well_known_types::timestamp::Timestamp>,
    #[serde(with="::protobuf_serde_helpers::MessageFieldDef")]
    // @@protoc_insertion_point(field:x.proto.ExampleMessageWithWellKnownTypes.struct)
    pub struct_: ::protobuf::MessageField<::protobuf::well_known_types::struct_::Struct>,
    // special fields
    #[serde(skip)]
    // @@protoc_insertion_point(special_field:x.proto.ExampleMessageWithWellKnownTypes.special_fields)
    pub special_fields: ::protobuf::SpecialFields,
}

but it doesn't work because ::protobuf::well_known_types::... aren't generated with customization:

error[E0277]: the trait bound `protobuf::well_known_types::duration::Duration: Deserialize<'_>` is not satisfied
    --> ....../example_rust_proto_pb_rs/example.rs:1526:30
     |
1526 | #[derive(::serde::Serialize, ::serde::Deserialize)]
     |                              ^^^^^^^^^^^^^^^^^^^^ the trait `Deserialize<'_>` is not implemented for `protobuf::well_known_types::duration::Duration`

I'll note that json and reflection support may work for a lot of use cases, however Serde is still useful for interoperability with other crates such as config.

neilisaac avatar Jun 07 '22 14:06 neilisaac

There are two options:

  • generate own well_known_types outside of protobuf crate (some hacking of rust-protobuf might be needed)
  • use remote feature of serde https://serde.rs/remote-derive.html

stepancheg avatar Jun 16 '22 01:06 stepancheg

@stepancheg I was thinking along the lines of the first approach. Could we add a flag to override the crate/submodule to reference well-known types from in generated code?

neilisaac avatar Jun 23 '22 21:06 neilisaac

@neilisaac I will accept PR, but it is unlikely I'll do it myself soon.

stepancheg avatar Jun 23 '22 21:06 stepancheg