Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/google/protobuf/internal/encoder.py: 18%
475 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:40 +0000
« prev ^ index » next coverage.py v7.3.2, created at 2023-12-08 06:40 +0000
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
8"""Code for encoding protocol message primitives.
10Contains the logic for encoding every logical protocol field type
11into one of the 5 physical wire types.
13This code is designed to push the Python interpreter's performance to the
14limits.
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.
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"""
44__author__ = 'kenton@google.com (Kenton Varda)'
46import struct
48from google.protobuf.internal import wire_format
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
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
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
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))
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.
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."""
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
127 return SpecificSizer
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."""
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
156 return SpecificSizer
159def _FixedSizer(value_size):
160 """Like _SimpleSizer except for a fixed-size field. The input is the size
161 of one value."""
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
182 return SpecificSizer
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.
192Int32Sizer = Int64Sizer = EnumSizer = _SimpleSizer(_SignedVarintSize)
194UInt32Sizer = UInt64Sizer = _SimpleSizer(_VarintSize)
196SInt32Sizer = SInt64Sizer = _ModifiedSizer(
197 _SignedVarintSize, wire_format.ZigZagEncode)
199Fixed32Sizer = SFixed32Sizer = FloatSizer = _FixedSizer(4)
200Fixed64Sizer = SFixed64Sizer = DoubleSizer = _FixedSizer(8)
202BoolSizer = _FixedSizer(1)
205def StringSizer(field_number, is_repeated, is_packed):
206 """Returns a sizer for a string field."""
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
227def BytesSizer(field_number, is_repeated, is_packed):
228 """Returns a sizer for a bytes field."""
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
249def GroupSizer(field_number, is_repeated, is_packed):
250 """Returns a sizer for a group field."""
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
267def MessageSizer(field_number, is_repeated, is_packed):
268 """Returns a sizer for a message field."""
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
288# --------------------------------------------------------------------
289# MessageSet is special: it needs custom logic to compute its size properly.
292def MessageSetItemSizer(field_number):
293 """Returns a sizer for extensions of MessageSet.
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
307 def FieldSize(value):
308 l = value.ByteSize()
309 return static_size + local_VarintSize(l) + l
311 return FieldSize
314# --------------------------------------------------------------------
315# Map is special: it needs custom logic to compute its size properly.
318def MapSizer(field_descriptor, is_message_map):
319 """Returns a sizer for a map field."""
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)
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
341 return FieldSize
343# ====================================================================
344# Encoders!
347def _VarintEncoder():
348 """Return an encoder for a basic varint value (does not include tag)."""
350 local_int2byte = struct.Struct('>B').pack
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))
361 return EncodeVarint
364def _SignedVarintEncoder():
365 """Return an encoder for a basic signed varint value (does not include
366 tag)."""
368 local_int2byte = struct.Struct('>B').pack
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))
381 return EncodeSignedVarint
384_EncodeVarint = _VarintEncoder()
385_EncodeSignedVarint = _SignedVarintEncoder()
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."""
392 pieces = []
393 _EncodeVarint(pieces.append, value, True)
394 return b"".join(pieces)
397def TagBytes(field_number, wire_type):
398 """Encode the given tag and return the bytes. Only called at startup."""
400 return bytes(_VarintBytes(wire_format.PackTag(field_number, wire_type)))
402# --------------------------------------------------------------------
403# As with sizers (see above), we have a number of common encoder
404# implementations.
407def _SimpleEncoder(wire_type, encode_value, compute_value_size):
408 """Return a constructor for an encoder for fields of a particular type.
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 """
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
445 return SpecificEncoder
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."""
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
479 return SpecificEncoder
482def _StructPackEncoder(wire_type, format):
483 """Return a constructor for an encoder for a fixed-width field.
485 Args:
486 wire_type: The field's wire type, for encoding tags.
487 format: The format string to pass to struct.pack().
488 """
490 value_size = struct.calcsize(format)
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
517 return SpecificEncoder
520def _FloatingPointEncoder(wire_type, format):
521 """Return a constructor for an encoder for float fields.
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.
527 Args:
528 wire_type: The field's wire type, for encoding tags.
529 format: The format string to pass to struct.pack().
530 """
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)
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
594 return SpecificEncoder
597# ====================================================================
598# Here we declare an encoder constructor for each field type. These work
599# very similarly to sizer constructors, described earlier.
602Int32Encoder = Int64Encoder = EnumEncoder = _SimpleEncoder(
603 wire_format.WIRETYPE_VARINT, _EncodeSignedVarint, _SignedVarintSize)
605UInt32Encoder = UInt64Encoder = _SimpleEncoder(
606 wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize)
608SInt32Encoder = SInt64Encoder = _ModifiedEncoder(
609 wire_format.WIRETYPE_VARINT, _EncodeVarint, _VarintSize,
610 wire_format.ZigZagEncode)
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')
624def BoolEncoder(field_number, is_repeated, is_packed):
625 """Returns an encoder for a boolean field."""
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
661def StringEncoder(field_number, is_repeated, is_packed):
662 """Returns an encoder for a string field."""
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
685def BytesEncoder(field_number, is_repeated, is_packed):
686 """Returns an encoder for a bytes field."""
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
707def GroupEncoder(field_number, is_repeated, is_packed):
708 """Returns an encoder for a group field."""
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
728def MessageEncoder(field_number, is_repeated, is_packed):
729 """Returns an encoder for a message field."""
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
749# --------------------------------------------------------------------
750# As before, MessageSet is special.
753def MessageSetItemEncoder(field_number):
754 """Encoder for extensions of MessageSet.
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
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)
778 return EncodeField
781# --------------------------------------------------------------------
782# As before, Map is special.
785def MapEncoder(field_descriptor):
786 """Encoder for extensions of MessageSet.
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)
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)
806 return EncodeField