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