• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
33Contains the logic for encoding every logical protocol field type
34into one of the 5 physical wire types.
35
36This code is designed to push the Python interpreter's performance to the
37limits.
38
39The basic idea is that at startup time, for every field (i.e. every
40FieldDescriptor) we construct two functions:  a "sizer" and an "encoder".  The
41sizer takes a value of this field's type and computes its byte size.  The
42encoder takes a writer function and a value.  It encodes the value into byte
43strings and invokes the writer function to write those strings.  Typically the
44writer function is the write() method of a cStringIO.
45
46We try to do as much work as possible when constructing the writer and the
47sizer 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@google.com (Kenton Varda)'
68
69import struct
70from 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
79def _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
93def _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
108def _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
123def _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
152def _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
181def _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
214Int32Sizer = Int64Sizer = EnumSizer = _SimpleSizer(_SignedVarintSize)
215
216UInt32Sizer = UInt64Sizer = _SimpleSizer(_VarintSize)
217
218SInt32Sizer = SInt64Sizer = _ModifiedSizer(
219    _SignedVarintSize, wire_format.ZigZagEncode)
220
221Fixed32Sizer = SFixed32Sizer = FloatSizer  = _FixedSizer(4)
222Fixed64Sizer = SFixed64Sizer = DoubleSizer = _FixedSizer(8)
223
224BoolSizer = _FixedSizer(1)
225
226
227def 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
249def 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
271def 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
289def 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
314def 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
340def _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
356def _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
379def _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
388def 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
398def _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
439def _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
473def _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
511def _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
593Int32Encoder = Int64Encoder = EnumEncoder = _SimpleEncoder(
594    wire_format.WIRETYPE_VARINT, _EncodeSignedVarint, _SignedVarintSize)
595
596UInt32Encoder = UInt64Encoder = _SimpleEncoder(
597    wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize)
598
599SInt32Encoder = 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).
607Fixed32Encoder  = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, '<I')
608Fixed64Encoder  = _StructPackEncoder(wire_format.WIRETYPE_FIXED64, '<Q')
609SFixed32Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED32, '<i')
610SFixed64Encoder = _StructPackEncoder(wire_format.WIRETYPE_FIXED64, '<q')
611FloatEncoder    = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED32, '<f')
612DoubleEncoder   = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED64, '<d')
613
614
615def 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
652def 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
676def 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
698def 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
719def 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
744def 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