-
Notifications
You must be signed in to change notification settings - Fork 508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optional default for message fields #521
Comments
I think this because proto3 spec re-support explicitly add label optional |
Any particular reason this was closed, @LucioFranco ? I second this request. I'm aware of the implications of field presence, but the As is, you either have to live with awkward/confusing code, or always add an extra type with manual mapping. This could potentially be supported with a Protobuf custom option, or a manual setting in |
Can you expand more on
I don't personally see this as a blocker for writing idiomatic code and that this models the way protobuf handles messages pretty well in the context of a type that is used to deser from the wire. |
This is mostly a problem for me where the Protobuf types are heavily used in business logic, not just for GRPC or other de/serialization. Fields with messages are very common, often to reuse types between messages. And often (at least in my use cases) these fields are guaranteed to be set, either because breaking changes are extremely unlikely and would require larger coordination across the codebase anyway, or because validation is done at the GRPC boundary. But when the corresponding Rust type is
As mentioned I usually remedy this by creating extra types with But that's a whole lot of work for something that would be fixed by Prost just generating the types as non-optional. (If you can be convinced I'd happily look into implementing this.) |
While I do think using the I would like to hear from others though cc @neoeinstein @danburkert |
It would be really helpful if some of the fields can be set using default / result in a deserialize error / panics. In most of the cases I just need to create a second struct(which is not backed by the proto file and needs manual maintainence) and unwrap every single |
So after some discussion on discord I decided that it would be helpful to discuss why would generating fields without wrapping in an
While this could be done ergonomically(With something like the /// imagine Foo is generated by prost-build
struct Foo {
pub bar: Option<Bar>,
}
struct Foo2<'a> {
pub bar: &'a Bar2,
}
impl<'a> From<&'a Foo> for Foo2<'a> {
fn from(value: &'a Foo) -> Self {
Self{
bar: value.bar.as_ref().unwrap().into(),
}
}
} Which is even more complicated than moving the fields into the new struct. Also the user will now need to keep the old struct around. As a comparison, serde allows declaring default attribute on a field, which allows the deserialization to still happen despite the field is not there: serde fill with the default given in struct definition. So serde allows it's user to choose: whether deal with a deserialization error, or declare the incentive and tell serde that they want a From prost-build's implementation's perspective, I guess we could go with the current solution where user gets to define An altenative way is to implement something like Sorry I'm not good at rust at all, actually I struggled to write the @LucioFranco Any feedback is welcome. |
This can give more insight about why messages are wrapped in |
Maybe supporting Google message Foo {
string name = 1 [(google.api.field_behavior) = REQUIRED];
} Its wildly use at Google, for instance in the pubsub api. For instance, if we take the google API example from the doc, if we take the // Request for the UpdateTopic method.
message UpdateTopicRequest {
// Required. The updated topic object.
Topic topic = 1 [(google.api.field_behavior) = REQUIRED];
// Required. Indicates which fields in the provided topic to update. Must be
// specified and non-empty. Note that if `update_mask` contains
// "message_storage_policy" but the `message_storage_policy` is not set in
// the `topic` provided above, then the updated value is determined by the
// policy configured at the project or organization level.
google.protobuf.FieldMask update_mask = 2
[(google.api.field_behavior) = REQUIRED];
} The generated code could be something like that : /// Request for the UpdateTopic method.
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct UpdateTopicRequest {
/// Required. The updated topic object.
#[prost(message, optional, tag = "1")]
pub topic: Topic,
/// Required. Indicates which fields in the provided topic to update. Must be
/// specified and non-empty. Note that if `update_mask` contains
/// "message_storage_policy" but the `message_storage_policy` is not set in
/// the `topic` provided above, then the updated value is determined by the
/// policy configured at the project or organization level.
#[prost(message, optional, tag = "2")]
pub update_mask: ::prost_types::FieldMask,
} We can optimize by removing the option hence we know it's a required field. |
Hi, This issue seems to be the most complete thread about the Problem with the optional field, that is logically required, is that it conflicts with the idiomatic Rust approach: you should not have data structures that will allow you to have your data in invalid state. For now the most idiomatic way to handle nested Now, the protobuf. Protocol buffers developers decided to get rid of the However, this issue been here for a while, and it seems there are still no decision on this matter. |
This totally make sense for me, I wonder maybe we should mention this in README? |
Hi,
I'd like to know if its reasonable/feasible to make message fields use
T
instead ofOption<T>
when deserialized ifT
implementsDefault
. For example, these messages:Could be deserialized as
I wonder if recursive messages would be a problem though.
The text was updated successfully, but these errors were encountered: