Home | History | Annotate | Download | only in internal
      1 # Protocol Buffers - Google's data interchange format
      2 # Copyright 2008 Google Inc.  All rights reserved.
      3 # http://code.google.com/p/protobuf/
      4 #
      5 # Redistribution and use in source and binary forms, with or without
      6 # modification, are permitted provided that the following conditions are
      7 # met:
      8 #
      9 #     * Redistributions of source code must retain the above copyright
     10 # notice, this list of conditions and the following disclaimer.
     11 #     * Redistributions in binary form must reproduce the above
     12 # copyright notice, this list of conditions and the following disclaimer
     13 # in the documentation and/or other materials provided with the
     14 # distribution.
     15 #     * Neither the name of Google Inc. nor the names of its
     16 # contributors may be used to endorse or promote products derived from
     17 # this software without specific prior written permission.
     18 #
     19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 """Code for encoding protocol message primitives.
     32 
     33 Contains the logic for encoding every logical protocol field type
     34 into one of the 5 physical wire types.
     35 
     36 This code is designed to push the Python interpreter's performance to the
     37 limits.
     38 
     39 The basic idea is that at startup time, for every field (i.e. every
     40 FieldDescriptor) we construct two functions:  a "sizer" and an "encoder".  The
     41 sizer takes a value of this field's type and computes its byte size.  The
     42 encoder takes a writer function and a value.  It encodes the value into byte
     43 strings and invokes the writer function to write those strings.  Typically the
     44 writer function is the write() method of a cStringIO.
     45 
     46 We try to do as much work as possible when constructing the writer and the
     47 sizer rather than when calling them.  In particular:
     48 * We copy any needed global functions to local variables, so that we do not need
     49   to do costly global table lookups at runtime.
     50 * Similarly, we try to do any attribute lookups at startup time if possible.
     51 * Every field's tag is encoded to bytes at startup, since it can't change at
     52   runtime.
     53 * Whatever component of the field size we can compute at startup, we do.
     54 * We *avoid* sharing code if doing so would make the code slower and not sharing
     55   does not burden us too much.  For example, encoders for repeated fields do
     56   not just call the encoders for singular fields in a loop because this would
     57   add an extra function call overhead for every loop iteration; instead, we
     58   manually inline the single-value encoder into the loop.
     59 * If a Python function lacks a return statement, Python actually generates
     60   instructions to pop the result of the last statement off the stack, push
     61   None onto the stack, and then return that.  If we really don't care what
     62   value is returned, then we can save two instructions by returning the
     63   result of the last statement.  It looks funny but it helps.
     64 * We assume that type and bounds checking has happened at a higher level.
     65 """
     66 
     67 __author__ = 'kenton (at] google.com (Kenton Varda)'
     68 
     69 import struct
     70 from google.protobuf.internal import wire_format
     71 
     72 
     73 # This will overflow and thus become IEEE-754 "infinity".  We would use
     74 # "float('inf')" but it doesn't work on Windows pre-Python-2.6.
     75 _POS_INF = 1e10000
     76 _NEG_INF = -_POS_INF
     77 
     78 
     79 def _VarintSize(value):
     80   """Compute the size of a varint value."""
     81   if value <= 0x7f: return 1
     82   if value <= 0x3fff: return 2
     83   if value <= 0x1fffff: return 3
     84   if value <= 0xfffffff: return 4
     85   if value <= 0x7ffffffff: return 5
     86   if value <= 0x3ffffffffff: return 6
     87   if value <= 0x1ffffffffffff: return 7
     88   if value <= 0xffffffffffffff: return 8
     89   if value <= 0x7fffffffffffffff: return 9
     90   return 10
     91 
     92 
     93 def _SignedVarintSize(value):
     94   """Compute the size of a signed varint value."""
     95   if value < 0: return 10
     96   if value <= 0x7f: return 1
     97   if value <= 0x3fff: return 2
     98   if value <= 0x1fffff: return 3
     99   if value <= 0xfffffff: return 4
    100   if value <= 0x7ffffffff: return 5
    101   if value <= 0x3ffffffffff: return 6
    102   if value <= 0x1ffffffffffff: return 7
    103   if value <= 0xffffffffffffff: return 8
    104   if value <= 0x7fffffffffffffff: return 9
    105   return 10
    106 
    107 
    108 def _TagSize(field_number):
    109   """Returns the number of bytes required to serialize a tag with this field
    110   number."""
    111   # Just pass in type 0, since the type won't affect the tag+type size.
    112   return _VarintSize(wire_format.PackTag(field_number, 0))
    113 
    114 
    115 # --------------------------------------------------------------------
    116 # In this section we define some generic sizers.  Each of these functions
    117 # takes parameters specific to a particular field type, e.g. int32 or fixed64.
    118 # It returns another function which in turn takes parameters specific to a
    119 # particular field, e.g. the field number and whether it is repeated or packed.
    120 # Look at the next section to see how these are used.
    121 
    122 
    123 def _SimpleSizer(compute_value_size):
    124   """A sizer which uses the function compute_value_size to compute the size of
    125   each value.  Typically compute_value_size is _VarintSize."""
    126 
    127   def SpecificSizer(field_number, is_repeated, is_packed):
    128     tag_size = _TagSize(field_number)
    129     if is_packed:
    130       local_VarintSize = _VarintSize
    131       def PackedFieldSize(value):
    132         result = 0
    133         for element in value:
    134           result += compute_value_size(element)
    135         return result + local_VarintSize(result) + tag_size
    136       return PackedFieldSize
    137     elif is_repeated:
    138       def RepeatedFieldSize(value):
    139         result = tag_size * len(value)
    140         for element in value:
    141           result += compute_value_size(element)
    142         return result
    143       return RepeatedFieldSize
    144     else:
    145       def FieldSize(value):
    146         return tag_size + compute_value_size(value)
    147       return FieldSize
    148 
    149   return SpecificSizer
    150 
    151 
    152 def _ModifiedSizer(compute_value_size, modify_value):
    153   """Like SimpleSizer, but modify_value is invoked on each value before it is
    154   passed to compute_value_size.  modify_value is typically ZigZagEncode."""
    155 
    156   def SpecificSizer(field_number, is_repeated, is_packed):
    157     tag_size = _TagSize(field_number)
    158     if is_packed:
    159       local_VarintSize = _VarintSize
    160       def PackedFieldSize(value):
    161         result = 0
    162         for element in value:
    163           result += compute_value_size(modify_value(element))
    164         return result + local_VarintSize(result) + tag_size
    165       return PackedFieldSize
    166     elif is_repeated:
    167       def RepeatedFieldSize(value):
    168         result = tag_size * len(value)
    169         for element in value:
    170           result += compute_value_size(modify_value(element))
    171         return result
    172       return RepeatedFieldSize
    173     else:
    174       def FieldSize(value):
    175         return tag_size + compute_value_size(modify_value(value))
    176       return FieldSize
    177 
    178   return SpecificSizer
    179 
    180 
    181 def _FixedSizer(value_size):
    182   """Like _SimpleSizer except for a fixed-size field.  The input is the size
    183   of one value."""
    184 
    185   def SpecificSizer(field_number, is_repeated, is_packed):
    186     tag_size = _TagSize(field_number)
    187     if is_packed:
    188       local_VarintSize = _VarintSize
    189       def PackedFieldSize(value):
    190         result = len(value) * value_size
    191         return result + local_VarintSize(result) + tag_size
    192       return PackedFieldSize
    193     elif is_repeated:
    194       element_size = value_size + tag_size
    195       def RepeatedFieldSize(value):
    196         return len(value) * element_size
    197       return RepeatedFieldSize
    198     else:
    199       field_size = value_size + tag_size
    200       def FieldSize(value):
    201         return field_size
    202       return FieldSize
    203 
    204   return SpecificSizer
    205 
    206 
    207 # ====================================================================
    208 # Here we declare a sizer constructor for each field type.  Each "sizer
    209 # constructor" is a function that takes (field_number, is_repeated, is_packed)
    210 # as parameters and returns a sizer, which in turn takes a field value as
    211 # a parameter and returns its encoded size.
    212 
    213 
    214 Int32Sizer = Int64Sizer = EnumSizer = _SimpleSizer(_SignedVarintSize)
    215 
    216 UInt32Sizer = UInt64Sizer = _SimpleSizer(_VarintSize)
    217 
    218 SInt32Sizer = SInt64Sizer = _ModifiedSizer(
    219     _SignedVarintSize, wire_format.ZigZagEncode)
    220 
    221 Fixed32Sizer = SFixed32Sizer = FloatSizer  = _FixedSizer(4)
    222 Fixed64Sizer = SFixed64Sizer = DoubleSizer = _FixedSizer(8)
    223 
    224 BoolSizer = _FixedSizer(1)
    225 
    226 
    227 def StringSizer(field_number, is_repeated, is_packed):
    228   """Returns a sizer for a string field."""
    229 
    230   tag_size = _TagSize(field_number)
    231   local_VarintSize = _VarintSize
    232   local_len = len
    233   assert not is_packed
    234   if is_repeated:
    235     def RepeatedFieldSize(value):
    236       result = tag_size * len(value)
    237       for element in value:
    238         l = local_len(element.encode('utf-8'))
    239         result += local_VarintSize(l) + l
    240       return result
    241     return RepeatedFieldSize
    242   else:
    243     def FieldSize(value):
    244       l = local_len(value.encode('utf-8'))
    245       return tag_size + local_VarintSize(l) + l
    246     return FieldSize
    247 
    248 
    249 def BytesSizer(field_number, is_repeated, is_packed):
    250   """Returns a sizer for a bytes field."""
    251 
    252   tag_size = _TagSize(field_number)
    253   local_VarintSize = _VarintSize
    254   local_len = len
    255   assert not is_packed
    256   if is_repeated:
    257     def RepeatedFieldSize(value):
    258       result = tag_size * len(value)
    259       for element in value:
    260         l = local_len(element)
    261         result += local_VarintSize(l) + l
    262       return result
    263     return RepeatedFieldSize
    264   else:
    265     def FieldSize(value):
    266       l = local_len(value)
    267       return tag_size + local_VarintSize(l) + l
    268     return FieldSize
    269 
    270 
    271 def GroupSizer(field_number, is_repeated, is_packed):
    272   """Returns a sizer for a group field."""
    273 
    274   tag_size = _TagSize(field_number) * 2
    275   assert not is_packed
    276   if is_repeated:
    277     def RepeatedFieldSize(value):
    278       result = tag_size * len(value)
    279       for element in value:
    280         result += element.ByteSize()
    281       return result
    282     return RepeatedFieldSize
    283   else:
    284     def FieldSize(value):
    285       return tag_size + value.ByteSize()
    286     return FieldSize
    287 
    288 
    289 def MessageSizer(field_number, is_repeated, is_packed):
    290   """Returns a sizer for a message field."""
    291 
    292   tag_size = _TagSize(field_number)
    293   local_VarintSize = _VarintSize
    294   assert not is_packed
    295   if is_repeated:
    296     def RepeatedFieldSize(value):
    297       result = tag_size * len(value)
    298       for element in value:
    299         l = element.ByteSize()
    300         result += local_VarintSize(l) + l
    301       return result
    302     return RepeatedFieldSize
    303   else:
    304     def FieldSize(value):
    305       l = value.ByteSize()
    306       return tag_size + local_VarintSize(l) + l
    307     return FieldSize
    308 
    309 
    310 # --------------------------------------------------------------------
    311 # MessageSet is special.
    312 
    313 
    314 def MessageSetItemSizer(field_number):
    315   """Returns a sizer for extensions of MessageSet.
    316 
    317   The message set message looks like this:
    318     message MessageSet {
    319       repeated group Item = 1 {
    320         required int32 type_id = 2;
    321         required string message = 3;
    322       }
    323     }
    324   """
    325   static_size = (_TagSize(1) * 2 + _TagSize(2) + _VarintSize(field_number) +
    326                  _TagSize(3))
    327   local_VarintSize = _VarintSize
    328 
    329   def FieldSize(value):
    330     l = value.ByteSize()
    331     return static_size + local_VarintSize(l) + l
    332 
    333   return FieldSize
    334 
    335 
    336 # ====================================================================
    337 # Encoders!
    338 
    339 
    340 def _VarintEncoder():
    341   """Return an encoder for a basic varint value (does not include tag)."""
    342 
    343   local_chr = chr
    344   def EncodeVarint(write, value):
    345     bits = value & 0x7f
    346     value >>= 7
    347     while value:
    348       write(local_chr(0x80|bits))
    349       bits = value & 0x7f
    350       value >>= 7
    351     return write(local_chr(bits))
    352 
    353   return EncodeVarint
    354 
    355 
    356 def _SignedVarintEncoder():
    357   """Return an encoder for a basic signed varint value (does not include
    358   tag)."""
    359 
    360   local_chr = chr
    361   def EncodeSignedVarint(write, value):
    362     if value < 0:
    363       value += (1 << 64)
    364     bits = value & 0x7f
    365     value >>= 7
    366     while value:
    367       write(local_chr(0x80|bits))
    368       bits = value & 0x7f
    369       value >>= 7
    370     return write(local_chr(bits))
    371 
    372   return EncodeSignedVarint
    373 
    374 
    375 _EncodeVarint = _VarintEncoder()
    376 _EncodeSignedVarint = _SignedVarintEncoder()
    377 
    378 
    379 def _VarintBytes(value):
    380   """Encode the given integer as a varint and return the bytes.  This is only
    381   called at startup time so it doesn't need to be fast."""
    382 
    383   pieces = []
    384   _EncodeVarint(pieces.append, value)
    385   return "".join(pieces)
    386 
    387 
    388 def TagBytes(field_number, wire_type):
    389   """Encode the given tag and return the bytes.  Only called at startup."""
    390 
    391   return _VarintBytes(wire_format.PackTag(field_number, wire_type))
    392 
    393 # --------------------------------------------------------------------
    394 # As with sizers (see above), we have a number of common encoder
    395 # implementations.
    396 
    397 
    398 def _SimpleEncoder(wire_type, encode_value, compute_value_size):
    399   """Return a constructor for an encoder for fields of a particular type.
    400 
    401   Args:
    402       wire_type:  The field's wire type, for encoding tags.
    403       encode_value:  A function which encodes an individual value, e.g.
    404         _EncodeVarint().
    405       compute_value_size:  A function which computes the size of an individual
    406         value, e.g. _VarintSize().
    407   """
    408 
    409   def SpecificEncoder(field_number, is_repeated, is_packed):
    410     if is_packed:
    411       tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
    412       local_EncodeVarint = _EncodeVarint
    413       def EncodePackedField(write, value):
    414         write(tag_bytes)
    415         size = 0
    416         for element in value:
    417           size += compute_value_size(element)
    418         local_EncodeVarint(write, size)
    419         for element in value:
    420           encode_value(write, element)
    421       return EncodePackedField
    422     elif is_repeated:
    423       tag_bytes = TagBytes(field_number, wire_type)
    424       def EncodeRepeatedField(write, value):
    425         for element in value:
    426           write(tag_bytes)
    427           encode_value(write, element)
    428       return EncodeRepeatedField
    429     else:
    430       tag_bytes = TagBytes(field_number, wire_type)
    431       def EncodeField(write, value):
    432         write(tag_bytes)
    433         return encode_value(write, value)
    434       return EncodeField
    435 
    436   return SpecificEncoder
    437 
    438 
    439 def _ModifiedEncoder(wire_type, encode_value, compute_value_size, modify_value):
    440   """Like SimpleEncoder but additionally invokes modify_value on every value
    441   before passing it to encode_value.  Usually modify_value is ZigZagEncode."""
    442 
    443   def SpecificEncoder(field_number, is_repeated, is_packed):
    444     if is_packed:
    445       tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
    446       local_EncodeVarint = _EncodeVarint
    447       def EncodePackedField(write, value):
    448         write(tag_bytes)
    449         size = 0
    450         for element in value:
    451           size += compute_value_size(modify_value(element))
    452         local_EncodeVarint(write, size)
    453         for element in value:
    454           encode_value(write, modify_value(element))
    455       return EncodePackedField
    456     elif is_repeated:
    457       tag_bytes = TagBytes(field_number, wire_type)
    458       def EncodeRepeatedField(write, value):
    459         for element in value:
    460           write(tag_bytes)
    461           encode_value(write, modify_value(element))
    462       return EncodeRepeatedField
    463     else:
    464       tag_bytes = TagBytes(field_number, wire_type)
    465       def EncodeField(write, value):
    466         write(tag_bytes)
    467         return encode_value(write, modify_value(value))
    468       return EncodeField
    469 
    470   return SpecificEncoder
    471 
    472 
    473 def _StructPackEncoder(wire_type, format):
    474   """Return a constructor for an encoder for a fixed-width field.
    475 
    476   Args:
    477       wire_type:  The field's wire type, for encoding tags.
    478       format:  The format string to pass to struct.pack().
    479   """
    480 
    481   value_size = struct.calcsize(format)
    482 
    483   def SpecificEncoder(field_number, is_repeated, is_packed):
    484     local_struct_pack = struct.pack
    485     if is_packed:
    486       tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
    487       local_EncodeVarint = _EncodeVarint
    488       def EncodePackedField(write, value):
    489         write(tag_bytes)
    490         local_EncodeVarint(write, len(value) * value_size)
    491         for element in value:
    492           write(local_struct_pack(format, element))
    493       return EncodePackedField
    494     elif is_repeated:
    495       tag_bytes = TagBytes(field_number, wire_type)
    496       def EncodeRepeatedField(write, value):
    497         for element in value:
    498           write(tag_bytes)
    499           write(local_struct_pack(format, element))
    500       return EncodeRepeatedField
    501     else:
    502       tag_bytes = TagBytes(field_number, wire_type)
    503       def EncodeField(write, value):
    504         write(tag_bytes)
    505         return write(local_struct_pack(format, value))
    506       return EncodeField
    507 
    508   return SpecificEncoder
    509 
    510 
    511 def _FloatingPointEncoder(wire_type, format):
    512   """Return a constructor for an encoder for float fields.
    513 
    514   This is like StructPackEncoder, but catches errors that may be due to
    515   passing non-finite floating-point values to struct.pack, and makes a
    516   second attempt to encode those values.
    517 
    518   Args:
    519       wire_type:  The field's wire type, for encoding tags.
    520       format:  The format string to pass to struct.pack().
    521   """
    522 
    523   value_size = struct.calcsize(format)
    524   if value_size == 4:
    525     def EncodeNonFiniteOrRaise(write, value):
    526       # Remember that the serialized form uses little-endian byte order.
    527       if value == _POS_INF:
    528         write('\x00\x00\x80\x7F')
    529       elif value == _NEG_INF:
    530         write('\x00\x00\x80\xFF')
    531       elif value != value:           # NaN
    532         write('\x00\x00\xC0\x7F')
    533       else:
    534         raise
    535   elif value_size == 8:
    536     def EncodeNonFiniteOrRaise(write, value):
    537       if value == _POS_INF:
    538         write('\x00\x00\x00\x00\x00\x00\xF0\x7F')
    539       elif value == _NEG_INF:
    540         write('\x00\x00\x00\x00\x00\x00\xF0\xFF')
    541       elif value != value:                         # NaN
    542         write('\x00\x00\x00\x00\x00\x00\xF8\x7F')
    543       else:
    544         raise
    545   else:
    546     raise ValueError('Can\'t encode floating-point values that are '
    547                      '%d bytes long (only 4 or 8)' % value_size)
    548 
    549   def SpecificEncoder(field_number, is_repeated, is_packed):
    550     local_struct_pack = struct.pack
    551     if is_packed:
    552       tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
    553       local_EncodeVarint = _EncodeVarint
    554       def EncodePackedField(write, value):
    555         write(tag_bytes)
    556         local_EncodeVarint(write, len(value) * value_size)
    557         for element in value:
    558           # This try/except block is going to be faster than any code that
    559           # we could write to check whether element is finite.
    560           try:
    561             write(local_struct_pack(format, element))
    562           except SystemError:
    563             EncodeNonFiniteOrRaise(write, element)
    564       return EncodePackedField
    565     elif is_repeated:
    566       tag_bytes = TagBytes(field_number, wire_type)
    567       def EncodeRepeatedField(write, value):
    568         for element in value:
    569           write(tag_bytes)
    570           try:
    571             write(local_struct_pack(format, element))
    572           except SystemError:
    573             EncodeNonFiniteOrRaise(write, element)
    574       return EncodeRepeatedField
    575     else:
    576       tag_bytes = TagBytes(field_number, wire_type)
    577       def EncodeField(write, value):
    578         write(tag_bytes)
    579         try:
    580           write(local_struct_pack(format, value))
    581         except SystemError:
    582           EncodeNonFiniteOrRaise(write, value)
    583       return EncodeField
    584 
    585   return SpecificEncoder
    586 
    587 
    588 # ====================================================================
    589 # Here we declare an encoder constructor for each field type.  These work
    590 # very similarly to sizer constructors, described earlier.
    591 
    592 
    593 Int32Encoder = Int64Encoder = EnumEncoder = _SimpleEncoder(
    594     wire_format.WIRETYPE_VARINT, _EncodeSignedVarint, _SignedVarintSize)
    595 
    596 UInt32Encoder = UInt64Encoder = _SimpleEncoder(
    597     wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize)
    598 
    599 SInt32Encoder = SInt64Encoder = _ModifiedEncoder(
    600     wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize,
    601     wire_format.ZigZagEncode)
    602 
    603 # Note that Python conveniently guarantees that when using the '<' prefix on
    604 # formats, they will also have the same size across all platforms (as opposed
    605 # to without the prefix, where their sizes depend on the C compiler's basic
    606 # type sizes).
    607 Fixed32Encoder  = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, '<I')
    608 Fixed64Encoder  = _StructPackEncoder(wire_format.WIRETYPE_FIXED64, '<Q')
    609 SFixed32Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, '<i')
    610 SFixed64Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED64, '<q')
    611 FloatEncoder    = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED32, '<f')
    612 DoubleEncoder   = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED64, '<d')
    613 
    614 
    615 def BoolEncoder(field_number, is_repeated, is_packed):
    616   """Returns an encoder for a boolean field."""
    617 
    618   false_byte = chr(0)
    619   true_byte = chr(1)
    620   if is_packed:
    621     tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
    622     local_EncodeVarint = _EncodeVarint
    623     def EncodePackedField(write, value):
    624       write(tag_bytes)
    625       local_EncodeVarint(write, len(value))
    626       for element in value:
    627         if element:
    628           write(true_byte)
    629         else:
    630           write(false_byte)
    631     return EncodePackedField
    632   elif is_repeated:
    633     tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
    634     def EncodeRepeatedField(write, value):
    635       for element in value:
    636         write(tag_bytes)
    637         if element:
    638           write(true_byte)
    639         else:
    640           write(false_byte)
    641     return EncodeRepeatedField
    642   else:
    643     tag_bytes = TagBytes(field_number, wire_format.WIRETYPE_VARINT)
    644     def EncodeField(write, value):
    645       write(tag_bytes)
    646       if value:
    647         return write(true_byte)
    648       return write(false_byte)
    649     return EncodeField
    650 
    651 
    652 def StringEncoder(field_number, is_repeated, is_packed):
    653   """Returns an encoder for a string field."""
    654 
    655   tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
    656   local_EncodeVarint = _EncodeVarint
    657   local_len = len
    658   assert not is_packed
    659   if is_repeated:
    660     def EncodeRepeatedField(write, value):
    661       for element in value:
    662         encoded = element.encode('utf-8')
    663         write(tag)
    664         local_EncodeVarint(write, local_len(encoded))
    665         write(encoded)
    666     return EncodeRepeatedField
    667   else:
    668     def EncodeField(write, value):
    669       encoded = value.encode('utf-8')
    670       write(tag)
    671       local_EncodeVarint(write, local_len(encoded))
    672       return write(encoded)
    673     return EncodeField
    674 
    675 
    676 def BytesEncoder(field_number, is_repeated, is_packed):
    677   """Returns an encoder for a bytes field."""
    678 
    679   tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
    680   local_EncodeVarint = _EncodeVarint
    681   local_len = len
    682   assert not is_packed
    683   if is_repeated:
    684     def EncodeRepeatedField(write, value):
    685       for element in value:
    686         write(tag)
    687         local_EncodeVarint(write, local_len(element))
    688         write(element)
    689     return EncodeRepeatedField
    690   else:
    691     def EncodeField(write, value):
    692       write(tag)
    693       local_EncodeVarint(write, local_len(value))
    694       return write(value)
    695     return EncodeField
    696 
    697 
    698 def GroupEncoder(field_number, is_repeated, is_packed):
    699   """Returns an encoder for a group field."""
    700 
    701   start_tag = TagBytes(field_number, wire_format.WIRETYPE_START_GROUP)
    702   end_tag = TagBytes(field_number, wire_format.WIRETYPE_END_GROUP)
    703   assert not is_packed
    704   if is_repeated:
    705     def EncodeRepeatedField(write, value):
    706       for element in value:
    707         write(start_tag)
    708         element._InternalSerialize(write)
    709         write(end_tag)
    710     return EncodeRepeatedField
    711   else:
    712     def EncodeField(write, value):
    713       write(start_tag)
    714       value._InternalSerialize(write)
    715       return write(end_tag)
    716     return EncodeField
    717 
    718 
    719 def MessageEncoder(field_number, is_repeated, is_packed):
    720   """Returns an encoder for a message field."""
    721 
    722   tag = TagBytes(field_number, wire_format.WIRETYPE_LENGTH_DELIMITED)
    723   local_EncodeVarint = _EncodeVarint
    724   assert not is_packed
    725   if is_repeated:
    726     def EncodeRepeatedField(write, value):
    727       for element in value:
    728         write(tag)
    729         local_EncodeVarint(write, element.ByteSize())
    730         element._InternalSerialize(write)
    731     return EncodeRepeatedField
    732   else:
    733     def EncodeField(write, value):
    734       write(tag)
    735       local_EncodeVarint(write, value.ByteSize())
    736       return value._InternalSerialize(write)
    737     return EncodeField
    738 
    739 
    740 # --------------------------------------------------------------------
    741 # As before, MessageSet is special.
    742 
    743 
    744 def MessageSetItemEncoder(field_number):
    745   """Encoder for extensions of MessageSet.
    746 
    747   The message set message looks like this:
    748     message MessageSet {
    749       repeated group Item = 1 {
    750         required int32 type_id = 2;
    751         required string message = 3;
    752       }
    753     }
    754   """
    755   start_bytes = "".join([
    756       TagBytes(1, wire_format.WIRETYPE_START_GROUP),
    757       TagBytes(2, wire_format.WIRETYPE_VARINT),
    758       _VarintBytes(field_number),
    759       TagBytes(3, wire_format.WIRETYPE_LENGTH_DELIMITED)])
    760   end_bytes = TagBytes(1, wire_format.WIRETYPE_END_GROUP)
    761   local_EncodeVarint = _EncodeVarint
    762 
    763   def EncodeField(write, value):
    764     write(start_bytes)
    765     local_EncodeVarint(write, value.ByteSize())
    766     value._InternalSerialize(write)
    767     return write(end_bytes)
    768 
    769   return EncodeField
    770