tafia / quick-protobuf

A rust implementation of protobuf parser
MIT License
452 stars 87 forks source link

protoc unable to parse quick-protobuf output and vice versa #161

Closed sdonnan closed 4 years ago

sdonnan commented 4 years ago

When I pass a buffer encoded with quick-protobuf (0.6.4) to protoc (libprotoc 3.0.0) it fails to parse it. I just use serialize_to_vec and write the vec to a file. The file is then cat into protoc --decode_raw.

The error message is "Failed to parse input."

I ended up here after trying to debug why a third party protobuf message couldn't be deserialized by the library but could be by protoc.

Serializing and deserializing just with quick-protobuf seems to work fine for me.

sdonnan commented 4 years ago

Here is a simplified example which shows the problem:

msg.proto

syntax = "proto2";

package tutorial;

message Person {
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;
}

message AddressBook {
    repeated Person people = 1;
    optional uint64 foo = 4;
    optional uint32 bar = 5;
}

python basline implementation (from protoc --python_out=py msg.proto)

import msg_pb2                                                                                                                                                                                                                                                                                                                                                                                                                                                                            m = msg_pb2.AddressBook()
m.foo = 8000
m.bar = 42

with open('py.raw','wb') as f:
    f.write(m.SerializeToString())

Generates 20c0 3e28 2a

rust baseline implementation (from pb-rs --output_directory quick-pb-ex/src msg.proto)

use quick_protobuf::{deserialize_from_slice, serialize_into_vec};
use std::io::prelude::*;                                                                                                                                                                                                                     
mod tutorial;

fn main() {
    let mut msg = tutorial::AddressBook::default();
    msg.foo = Some(8000);
    msg.bar = Some(42);                                                                                                                                                                                                                      
    let buf = serialize_into_vec(&msg).unwrap();

    std::fs::File::create("rs.raw").unwrap().write(&buf).unwrap();
}

Generates 0520 c03e 282a

Checking output with protoc

> rs.raw | protoc msg.proto --decode=tutorial.AddressBook
Failed to parse input.
> cat py/py.raw | protoc msg.proto --decode=tutorial.AddressBook
foo: 8000
bar: 42
sdonnan commented 4 years ago

Its now obvious that the serialize_into_vec function creates a protobuf message stream rather than a standalone serialized protobuf message. This is different from the Google API. Not sure if its a bug but it is certainly unexpected.

~I can see documentation for the from_reader approach but it does not seem to be implemented in the released code generator (or at least I haven't found it yet).~ Didn't use the trait. Whoops.