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