diff options
Diffstat (limited to 'generator/google/protobuf/internal/encoder.py')
-rw-r--r-- | generator/google/protobuf/internal/encoder.py | 92 |
1 files changed, 73 insertions, 19 deletions
diff --git a/generator/google/protobuf/internal/encoder.py b/generator/google/protobuf/internal/encoder.py index 777975e..48ef2df 100644 --- a/generator/google/protobuf/internal/encoder.py +++ b/generator/google/protobuf/internal/encoder.py @@ -1,6 +1,6 @@ # Protocol Buffers - Google's data interchange format # Copyright 2008 Google Inc. All rights reserved. -# http://code.google.com/p/protobuf/ +# https://developers.google.com/protocol-buffers/ # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are @@ -41,7 +41,7 @@ FieldDescriptor) we construct two functions: a "sizer" and an "encoder". The sizer takes a value of this field's type and computes its byte size. The encoder takes a writer function and a value. It encodes the value into byte strings and invokes the writer function to write those strings. Typically the -writer function is the write() method of a cStringIO. +writer function is the write() method of a BytesIO. We try to do as much work as possible when constructing the writer and the sizer rather than when calling them. In particular: @@ -67,6 +67,9 @@ sizer rather than when calling them. In particular: __author__ = 'kenton@google.com (Kenton Varda)' import struct + +import six + from google.protobuf.internal import wire_format @@ -308,7 +311,7 @@ def MessageSizer(field_number, is_repeated, is_packed): # -------------------------------------------------------------------- -# MessageSet is special. +# MessageSet is special: it needs custom logic to compute its size properly. def MessageSetItemSizer(field_number): @@ -333,6 +336,32 @@ def MessageSetItemSizer(field_number): return FieldSize +# -------------------------------------------------------------------- +# Map is special: it needs custom logic to compute its size properly. + + +def MapSizer(field_descriptor): + """Returns a sizer for a map field.""" + + # Can't look at field_descriptor.message_type._concrete_class because it may + # not have been initialized yet. + message_type = field_descriptor.message_type + message_sizer = MessageSizer(field_descriptor.number, False, False) + + def FieldSize(map_value): + total = 0 + for key in map_value: + value = map_value[key] + # It's wasteful to create the messages and throw them away one second + # later since we'll do the same for the actual encode. But there's not an + # obvious way to avoid this within the current design without tons of code + # duplication. + entry_msg = message_type._concrete_class(key=key, value=value) + total += message_sizer(entry_msg) + return total + + return FieldSize + # ==================================================================== # Encoders! @@ -340,15 +369,14 @@ def MessageSetItemSizer(field_number): def _VarintEncoder(): """Return an encoder for a basic varint value (does not include tag).""" - local_chr = chr def EncodeVarint(write, value): bits = value & 0x7f value >>= 7 while value: - write(local_chr(0x80|bits)) + write(six.int2byte(0x80|bits)) bits = value & 0x7f value >>= 7 - return write(local_chr(bits)) + return write(six.int2byte(bits)) return EncodeVarint @@ -357,17 +385,16 @@ def _SignedVarintEncoder(): """Return an encoder for a basic signed varint value (does not include tag).""" - local_chr = chr def EncodeSignedVarint(write, value): if value < 0: value += (1 << 64) bits = value & 0x7f value >>= 7 while value: - write(local_chr(0x80|bits)) + write(six.int2byte(0x80|bits)) bits = value & 0x7f value >>= 7 - return write(local_chr(bits)) + return write(six.int2byte(bits)) return EncodeSignedVarint @@ -382,7 +409,7 @@ def _VarintBytes(value): pieces = [] _EncodeVarint(pieces.append, value) - return "".join(pieces) + return b"".join(pieces) def TagBytes(field_number, wire_type): @@ -525,21 +552,21 @@ def _FloatingPointEncoder(wire_type, format): def EncodeNonFiniteOrRaise(write, value): # Remember that the serialized form uses little-endian byte order. if value == _POS_INF: - write('\x00\x00\x80\x7F') + write(b'\x00\x00\x80\x7F') elif value == _NEG_INF: - write('\x00\x00\x80\xFF') + write(b'\x00\x00\x80\xFF') elif value != value: # NaN - write('\x00\x00\xC0\x7F') + write(b'\x00\x00\xC0\x7F') else: raise elif value_size == 8: def EncodeNonFiniteOrRaise(write, value): if value == _POS_INF: - write('\x00\x00\x00\x00\x00\x00\xF0\x7F') + write(b'\x00\x00\x00\x00\x00\x00\xF0\x7F') elif value == _NEG_INF: - write('\x00\x00\x00\x00\x00\x00\xF0\xFF') + write(b'\x00\x00\x00\x00\x00\x00\xF0\xFF') elif value != value: # NaN - write('\x00\x00\x00\x00\x00\x00\xF8\x7F') + write(b'\x00\x00\x00\x00\x00\x00\xF8\x7F') else: raise else: @@ -615,8 +642,8 @@ DoubleEncoder = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED64, '<d') def BoolEncoder(field_number, is_repeated, is_packed): """Returns an encoder for a boolean field.""" - false_byte = chr(0) - true_byte = chr(1) + false_byte = b'\x00' + true_byte = b'\x01' if is_packed: tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED) local_EncodeVarint = _EncodeVarint @@ -752,7 +779,7 @@ def MessageSetItemEncoder(field_number): } } """ - start_bytes = "".join([ + start_bytes = b"".join([ TagBytes(1, wire_format.WIRETYPE_START_GROUP), TagBytes(2, wire_format.WIRETYPE_VARINT), _VarintBytes(field_number), @@ -767,3 +794,30 @@ def MessageSetItemEncoder(field_number): return write(end_bytes) return EncodeField + + +# -------------------------------------------------------------------- +# As before, Map is special. + + +def MapEncoder(field_descriptor): + """Encoder for extensions of MessageSet. + + Maps always have a wire format like this: + message MapEntry { + key_type key = 1; + value_type value = 2; + } + repeated MapEntry map = N; + """ + # Can't look at field_descriptor.message_type._concrete_class because it may + # not have been initialized yet. + message_type = field_descriptor.message_type + encode_message = MessageEncoder(field_descriptor.number, False, False) + + def EncodeField(write, value): + for key in value: + entry_msg = message_type._concrete_class(key=key, value=value[key]) + encode_message(write, entry_msg) + + return EncodeField |