blob: 777975e82e042b277be6ff6b1dae3b4f5cf6fa57 [file] [log] [blame]
temporal40ee5512008-07-10 02:12:20 +00001# Protocol Buffers - Google's data interchange format
kenton@google.com24bf56f2008-09-24 20:31:01 +00002# Copyright 2008 Google Inc. All rights reserved.
temporal40ee5512008-07-10 02:12:20 +00003# http://code.google.com/p/protobuf/
4#
kenton@google.com24bf56f2008-09-24 20:31:01 +00005# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met:
temporal40ee5512008-07-10 02:12:20 +00008#
kenton@google.com24bf56f2008-09-24 20:31:01 +00009# * 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.
temporal40ee5512008-07-10 02:12:20 +000018#
kenton@google.com24bf56f2008-09-24 20:31:01 +000019# 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.
temporal40ee5512008-07-10 02:12:20 +000030
kenton@google.comfccb1462009-12-18 02:11:36 +000031"""Code for encoding protocol message primitives.
temporal40ee5512008-07-10 02:12:20 +000032
33Contains the logic for encoding every logical protocol field type
34into one of the 5 physical wire types.
kenton@google.comfccb1462009-12-18 02:11:36 +000035
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.
temporal40ee5512008-07-10 02:12:20 +000065"""
66
kenton@google.comfccb1462009-12-18 02:11:36 +000067__author__ = 'kenton@google.com (Kenton Varda)'
temporal40ee5512008-07-10 02:12:20 +000068
69import struct
temporal40ee5512008-07-10 02:12:20 +000070from google.protobuf.internal import wire_format
temporal40ee5512008-07-10 02:12:20 +000071
72
liujisi@google.com33165fe2010-11-02 13:14:58 +000073# 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
kenton@google.comfccb1462009-12-18 02:11:36 +000079def _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
temporal40ee5512008-07-10 02:12:20 +000091
92
kenton@google.comfccb1462009-12-18 02:11:36 +000093def _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
kenton@google.com2d6daa72009-01-22 01:27:00 +0000106
107
kenton@google.comfccb1462009-12-18 02:11:36 +0000108def _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))
kenton@google.com2d6daa72009-01-22 01:27:00 +0000113
kenton@google.com2d6daa72009-01-22 01:27:00 +0000114
kenton@google.comfccb1462009-12-18 02:11:36 +0000115# --------------------------------------------------------------------
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.
kenton@google.com2d6daa72009-01-22 01:27:00 +0000121
kenton@google.com2d6daa72009-01-22 01:27:00 +0000122
kenton@google.comfccb1462009-12-18 02:11:36 +0000123def _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."""
kenton@google.com2d6daa72009-01-22 01:27:00 +0000126
kenton@google.comfccb1462009-12-18 02:11:36 +0000127 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
kenton@google.com2d6daa72009-01-22 01:27:00 +0000148
kenton@google.comfccb1462009-12-18 02:11:36 +0000149 return SpecificSizer
kenton@google.com2d6daa72009-01-22 01:27:00 +0000150
kenton@google.com2d6daa72009-01-22 01:27:00 +0000151
kenton@google.comfccb1462009-12-18 02:11:36 +0000152def _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."""
kenton@google.com2d6daa72009-01-22 01:27:00 +0000155
kenton@google.comfccb1462009-12-18 02:11:36 +0000156 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
kenton@google.com2d6daa72009-01-22 01:27:00 +0000177
kenton@google.comfccb1462009-12-18 02:11:36 +0000178 return SpecificSizer
kenton@google.com2d6daa72009-01-22 01:27:00 +0000179
temporal40ee5512008-07-10 02:12:20 +0000180
kenton@google.comfccb1462009-12-18 02:11:36 +0000181def _FixedSizer(value_size):
182 """Like _SimpleSizer except for a fixed-size field. The input is the size
183 of one value."""
temporal40ee5512008-07-10 02:12:20 +0000184
kenton@google.comfccb1462009-12-18 02:11:36 +0000185 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
temporal40ee5512008-07-10 02:12:20 +0000203
kenton@google.comfccb1462009-12-18 02:11:36 +0000204 return SpecificSizer
temporal40ee5512008-07-10 02:12:20 +0000205
temporal40ee5512008-07-10 02:12:20 +0000206
kenton@google.comfccb1462009-12-18 02:11:36 +0000207# ====================================================================
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.
temporal40ee5512008-07-10 02:12:20 +0000212
temporal40ee5512008-07-10 02:12:20 +0000213
kenton@google.comfccb1462009-12-18 02:11:36 +0000214Int32Sizer = Int64Sizer = EnumSizer = _SimpleSizer(_SignedVarintSize)
temporal40ee5512008-07-10 02:12:20 +0000215
kenton@google.comfccb1462009-12-18 02:11:36 +0000216UInt32Sizer = UInt64Sizer = _SimpleSizer(_VarintSize)
temporal40ee5512008-07-10 02:12:20 +0000217
kenton@google.comfccb1462009-12-18 02:11:36 +0000218SInt32Sizer = SInt64Sizer = _ModifiedSizer(
219 _SignedVarintSize, wire_format.ZigZagEncode)
temporal40ee5512008-07-10 02:12:20 +0000220
kenton@google.comfccb1462009-12-18 02:11:36 +0000221Fixed32Sizer = 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;
temporal40ee5512008-07-10 02:12:20 +0000322 }
kenton@google.comfccb1462009-12-18 02:11:36 +0000323 }
324 """
325 static_size = (_TagSize(1) * 2 + _TagSize(2) + _VarintSize(field_number) +
326 _TagSize(3))
327 local_VarintSize = _VarintSize
temporal40ee5512008-07-10 02:12:20 +0000328
kenton@google.comfccb1462009-12-18 02:11:36 +0000329 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
liujisi@google.com33165fe2010-11-02 13:14:58 +0000511def _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
kenton@google.comfccb1462009-12-18 02:11:36 +0000588# ====================================================================
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')
liujisi@google.com33165fe2010-11-02 13:14:58 +0000611FloatEncoder = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED32, '<f')
612DoubleEncoder = _FloatingPointEncoder(wire_format.WIRETYPE_FIXED64, '<d')
kenton@google.comfccb1462009-12-18 02:11:36 +0000613
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