-
Notifications
You must be signed in to change notification settings - Fork 504
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
Map<_,type> appears to fail for zero types #99
Comments
The language guide says that map fields are treated as repeated key/value message types, so I believe |
The map encoding code goes way out of it's way to do this optimization, so at some point in the past I decided this was an important optimization, although I can't remember why now. Perhaps it's checked in the conformance tests. |
With equivalent C++ code, C++ protobuf generates 0a070a0376616c1000 which does include the default value, so I do not think this is required for conformance (I assume C++ protobuf is conformant). C++ protobuf also accepts 0a070a0368656a as input (without the encoded zero). I think prost is not wrong here. |
I'll close then (Also, I don't believe C++ can be wrong. It's the reference implementation if I'm not mistaken?) |
FWIW I'm still not convinced |
A guess as to why you could have thought of this optimization (or whatever you'd like to call it) as important: Because of Prost's way to represent messages as plain Rust structs, if this optimization wouldn't be there, a proto message with many int fields would take noticeable amount of space when serialized even when the object is just Not saying that it has to be kept, but that seems like a somewhat useful feature to me. |
Removes an optimization that skipped encoding default map values. fixes #99
I looked into what it would look like to change the behavior so that map keys are always encoded. It ends up making some of the most complicated code in I'm curious if y'all have thoughts. |
That's definitely the case for |
Fwiw, this breaks with the the following configuration: [server: tonic/prost] -> [envoy] -> [dart/flutter using grpc-web]. Dart experiences a Code 15 Unrecoverable data loss or corruption. A go server implementing the same grpc service responds with the encoded 0 (confirmed with wireshark) for my |
This is the right thing to do according to proto spec: https://github.com/protocolbuffers/protobuf/blob/main/docs/field_presence.md#presence-in-tag-value-stream-wire-format-serialization
Encoding of map fields are specified in https://developers.google.com/protocol-buffers/docs/proto#maps In proto syntax, if you have a map field like map<int32, MyMapValue> my_map_field = 123; It's encoded as if it was repeated MyMapFieldEntry my_map_field = 123; where message MyMapFieldEntry {
optional int32 key = 1;
optional MyMapValue value = 2;
} In the original example, map value type is For Dart protobuf implementation, we fix the decoding for map fields to handle this case in google/protobuf.dart#745. Note that since both key and value fields of map entries are optional, it's also possible to omit the key field. For example message Foo {
map<int32, int32> bar = 1;
} let mut x = Foo::default();
x.bar.insert(0, 0); A spec compliant implementation should encode
|
@osa1 thanks for the explanation, so I guess we can close this now since this isn't really a bug with prost? |
Thinking more about this, I'm not as confident now that this is not a bug. In the spec I quoted in my comment above:
Here I missed the "fields with no presence" part. message MapFieldEntry {
optional key_type key = 1;
optional value_type value = 2;
}
repeated MapFieldEntry map_field = N; Not encoding a default value (in key or value fields) is actually different than encoding it, because Now, the question is what happens on the receiving end when you get a map entry with missing key, value, or both key and value fields, and you represent proto Unfortunately, protobuf spec does not specify what the default values should be for What this means is, if you have a To avoid this problem prost may want to serialize the value fields always. I'm not sure if not doing it is a bug or not. |
I asked this to protobuf team (in context of google/protobuf.dart#309). It's fine if an implementation omits key or value of a map entry when the value is the default for the field type. So prost's behavior seems fine, and if an implementation cannot handle it then it's a bug in that implementation. (this is what we fix in the PR linked above) That said, official protobuf implementation will never omit key or value fields, even when they have the default value for the type: https://github.com/protocolbuffers/protobuf/blob/8d3a7327606b115dda871be54c8b8cb66d41ff90/src/google/protobuf/wire_format.cc#L1184-L1203 I'm guessing other protobuf implementation by the protobuf team (e.g. the JS one linked in the bug report) also do the same, and that's why they cannot handle when key or value fields are missing. When sending they always serialize those fields so the case where one or both of the fields are missing is not considered and tested. |
Ok thanks for the update, I will close this issue since the implementation seems correct. |
I'll be honest, I'm not 100% certain if this is a prost issue of an issue with the Javascript library, but since I'm using the one included in Google's own tree:
https://github.com/google/protobuf/tree/master/js
I'm inclined to try here first. The issue is with the following code:
In Rust
Now encode and send it somewhere. Prost appears to only write the key, and not the subsequent value of 0. At least in Javascript, this causes a panic due to receiving a key with a missing value, leading me to have to use string types and conversions back and forth from numbers in order to bypass this.
This applies to all zero types, floats/doubles do this on
0.0
, bools do this onfalse
.It's possible the specification allows this and the Javascript is in error, but again, I'm trying here first since I think this is more likely a prost bug.
The text was updated successfully, but these errors were encountered: