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