This is the inverse of protobuf_serialize_to_codes/3 
-- it takes a wire stream (list of codes) and creates a
dict. The dict tags 
are the fully qualified names of the messages. Repeated fields that 
aren't in the wire stream get set to the value []; other 
fields that aren't in the wire stream get their default value (typically 
the empty string or zero, depending on type). Embedded messages and 
groups are omitted if not in the wire stream; you can test for their 
presence using
get_dict/3. Enums are looked up and 
converted to atoms; bools are represented by
false and true; strings are represented by 
Prolog strings (not atoms); bytes are represented by lists of codes.
There is no mechanism for determining whether a field was in the wire 
stream or not (that is, there is no equivalent of the Python 
implementation's HasField).
The "oneof" feature causes a slightly different behavior. Only the field that's in the wire stream gets set; the other fields are omitted. And if none of the fields in the "oneof" are set, then none of the fields appears. You can check which field is set by using get_dict/3.
Currently, there is no special support for the protobuf "map" feature. It is treated as an ordinary message field. The convenience predicates protobuf_field_is_map/3 and protobuf_map_pairs/3 can be used to convert between a "map" field and a key-value list, which gives you the freedom to use any kind of association list for the map. See also Issue #12 For example:
message MapMessage {
  map<string, sint64> number_ints = 5;
}
is treated as if it is
message MapMessage {
  message KeyValue {
    optional string  Key = 1;
    optional sint64  Value = 2;
  }
  repeated KeyValue number_ints = 5;
}
You can handle this on input by
protobuf_parse_from_codes(WireCodes, 'MapMessage', Term), protobuf_map_pairs(Term.number_ints, _, Pairs).
and on output by
protobuf_map_pairs(TermNnumberInts, _, Pairs),
protobuf_serialize_to_codes(_{number_ints:TermNumberInts}, WireCodes).