OLD | NEW |
| (Empty) |
1 # Copyright 2014 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 """ | |
6 The descriptors used to define generated elements of the mojo python bindings. | |
7 """ | |
8 | |
9 import array | |
10 import itertools | |
11 import struct | |
12 | |
13 import mojo_bindings.reflection as reflection | |
14 import mojo_bindings.serialization as serialization | |
15 | |
16 # pylint: disable=E0611,F0401 | |
17 import mojo_system | |
18 | |
19 | |
20 class Type(object): | |
21 """Describes the type of a struct field or a method parameter,""" | |
22 | |
23 def Convert(self, value): # pylint: disable=R0201 | |
24 """ | |
25 Convert the given value into its canonical representation, raising an | |
26 exception if the value cannot be converted. | |
27 """ | |
28 return value | |
29 | |
30 def GetDefaultValue(self, value): | |
31 """ | |
32 Returns the default value for this type associated with the given value. | |
33 This method must be able to correcly handle value being None. | |
34 """ | |
35 return self.Convert(value) | |
36 | |
37 def IsUnion(self): | |
38 """ | |
39 Returns true if the type is a union. This is necessary to be able to | |
40 identify a union when descriptor.py cannot be imported. | |
41 """ | |
42 return False | |
43 | |
44 | |
45 class SerializableType(Type): | |
46 """Describe a type that can be serialized by itself.""" | |
47 | |
48 def __init__(self, typecode): | |
49 Type.__init__(self) | |
50 self.typecode = typecode | |
51 self.byte_size = struct.calcsize('<%s' % self.GetTypeCode()) | |
52 | |
53 def GetTypeCode(self): | |
54 """ | |
55 Returns the type code (as defined by the struct module) used to encode | |
56 this type. | |
57 """ | |
58 return self.typecode | |
59 | |
60 def GetByteSize(self): | |
61 """ | |
62 Returns the size of the encoding of this type. | |
63 """ | |
64 return self.byte_size | |
65 | |
66 def GetAlignment(self): | |
67 """ | |
68 Returns the alignment required by the encoding of this type. By default it | |
69 is set to the byte size of the biggest packed value. | |
70 """ | |
71 return max([struct.calcsize('<%s' % c) for c in self.GetTypeCode()]) | |
72 | |
73 def Serialize(self, value, data_offset, data, handle_offset): | |
74 """ | |
75 Serialize a value of this type. | |
76 | |
77 Args: | |
78 value: the value to serialize. | |
79 data_offset: the offset to the end of the data bytearray. Used to encode | |
80 pointers. | |
81 data: the bytearray to append additional data to. | |
82 handle_offset: the offset to use to encode handles. | |
83 | |
84 Returns a a tuple where the first element is the value to encode, and the | |
85 second is the array of handles to add to the message. | |
86 """ | |
87 raise NotImplementedError() | |
88 | |
89 def Deserialize(self, value, context): | |
90 """ | |
91 Deserialize a value of this type. | |
92 | |
93 Args: | |
94 value: the base value for this type. This is always a numeric type, and | |
95 corresponds to the first element in the tuple returned by | |
96 Serialize. | |
97 data: the bytearray to retrieve additional data from. | |
98 handles: the array of handles contained in the message to deserialize. | |
99 | |
100 Returns the deserialized value. | |
101 """ | |
102 raise NotImplementedError() | |
103 | |
104 | |
105 class BooleanType(SerializableType): | |
106 """Type object for booleans""" | |
107 | |
108 def Convert(self, value): | |
109 return bool(value) | |
110 | |
111 def Serialize(self, value, data_offset, data, handle_offset): | |
112 return (_ConvertBooleansToByte([value]), []) | |
113 | |
114 def Deserialize(self, value, context): | |
115 return _ConvertByteToBooleans(value, 1)[0] | |
116 | |
117 | |
118 class NumericType(SerializableType): | |
119 """Base Type object for all numeric types""" | |
120 | |
121 def GetDefaultValue(self, value): | |
122 if value is None: | |
123 return self.Convert(0) | |
124 return self.Convert(value) | |
125 | |
126 def Serialize(self, value, data_offset, data, handle_offset): | |
127 return (value, []) | |
128 | |
129 def Deserialize(self, value, context): | |
130 return value | |
131 | |
132 | |
133 class IntegerType(NumericType): | |
134 """Type object for integer types.""" | |
135 | |
136 def __init__(self, typecode): | |
137 NumericType.__init__(self, typecode) | |
138 size = 8 * self.byte_size | |
139 signed = typecode.islower() | |
140 if signed: | |
141 self._min_value = -(1 << (size - 1)) | |
142 self._max_value = (1 << (size - 1)) - 1 | |
143 else: | |
144 self._min_value = 0 | |
145 self._max_value = (1 << size) - 1 | |
146 | |
147 def Convert(self, value): | |
148 if value is None: | |
149 raise TypeError('None is not an integer.') | |
150 if not isinstance(value, (int, long)): | |
151 raise TypeError('%r is not an integer type' % value) | |
152 if value < self._min_value or value > self._max_value: | |
153 raise OverflowError('%r is not in the range [%d, %d]' % | |
154 (value, self._min_value, self._max_value)) | |
155 return value | |
156 | |
157 | |
158 class FloatType(NumericType): | |
159 """Type object for floating point number types.""" | |
160 | |
161 def Convert(self, value): | |
162 if value is None: | |
163 raise TypeError('None is not an floating point number.') | |
164 if not isinstance(value, (int, long, float)): | |
165 raise TypeError('%r is not a numeric type' % value) | |
166 return float(value) | |
167 | |
168 | |
169 class UnionType(SerializableType): | |
170 """Base Type object for union.""" | |
171 | |
172 def __init__(self, union_type_getter, nullable=False): | |
173 SerializableType.__init__(self, 'IIQ') | |
174 self.nullable = nullable | |
175 self._union_type_getter = union_type_getter | |
176 self._union_type = None | |
177 | |
178 def IsUnion(self): | |
179 return True | |
180 | |
181 @property | |
182 def union_type(self): | |
183 if not self._union_type: | |
184 self._union_type = self._union_type_getter() | |
185 return self._union_type | |
186 | |
187 def Serialize(self, value, data_offset, data, handle_offset): | |
188 if not value: | |
189 if not self.nullable: | |
190 raise serialization.SerializationException( | |
191 'Trying to serialize null for non nullable type.') | |
192 return ((0, 0, 0), []) | |
193 | |
194 ((size, tag, entry, new_data), new_handles) = ( | |
195 value.SerializeInline(handle_offset)) | |
196 if len(new_data) > 0: | |
197 data.extend(new_data) | |
198 entry = data_offset - 8 | |
199 | |
200 return ((size, tag, entry), new_handles) | |
201 | |
202 def Deserialize(self, value, context): | |
203 result = self.union_type.Deserialize(context) | |
204 if not result and not self.nullable: | |
205 raise serialization.DeserializationException( | |
206 'Trying to deserialize null for non nullable type.') | |
207 return result | |
208 | |
209 | |
210 class PointerType(SerializableType): | |
211 """Base Type object for pointers.""" | |
212 | |
213 def __init__(self, nullable=False): | |
214 SerializableType.__init__(self, 'Q') | |
215 self.nullable = nullable | |
216 | |
217 def Serialize(self, value, data_offset, data, handle_offset): | |
218 if value is None and not self.nullable: | |
219 raise serialization.SerializationException( | |
220 'Trying to serialize null for non nullable type.') | |
221 if value is None: | |
222 return (0, []) | |
223 return self.SerializePointer(value, data_offset, data, handle_offset) | |
224 | |
225 def Deserialize(self, value, context): | |
226 if value == 0: | |
227 if not self.nullable: | |
228 raise serialization.DeserializationException( | |
229 'Trying to deserialize null for non nullable type.') | |
230 return None | |
231 if value % 8 != 0: | |
232 raise serialization.DeserializationException( | |
233 'Pointer alignment is incorrect.') | |
234 sub_context = context.GetSubContext(value) | |
235 if len(sub_context.data) < serialization.HEADER_STRUCT.size: | |
236 raise serialization.DeserializationException( | |
237 'Available data too short to contain header.') | |
238 (size, nb_elements) = serialization.HEADER_STRUCT.unpack_from( | |
239 sub_context.data) | |
240 if len(sub_context.data) < size or size < serialization.HEADER_STRUCT.size: | |
241 raise serialization.DeserializationException('Header size is incorrect.') | |
242 sub_context.ClaimMemory(0, size) | |
243 return self.DeserializePointer(size, nb_elements, sub_context) | |
244 | |
245 def SerializePointer(self, value, data_offset, data, handle_offset): | |
246 """Serialize the not null value.""" | |
247 raise NotImplementedError() | |
248 | |
249 def DeserializePointer(self, size, nb_elements, context): | |
250 raise NotImplementedError() | |
251 | |
252 | |
253 class StringType(PointerType): | |
254 """ | |
255 Type object for strings. | |
256 | |
257 Strings are represented as unicode, and the conversion is done using the | |
258 default encoding if a string instance is used. | |
259 """ | |
260 | |
261 def __init__(self, nullable=False): | |
262 PointerType.__init__(self, nullable) | |
263 self._array_type = NativeArrayType('B', nullable) | |
264 | |
265 def Convert(self, value): | |
266 if value is None or isinstance(value, unicode): | |
267 return value | |
268 if isinstance(value, str): | |
269 return unicode(value) | |
270 raise TypeError('%r is not a string' % value) | |
271 | |
272 def SerializePointer(self, value, data_offset, data, handle_offset): | |
273 string_array = array.array('b') | |
274 string_array.fromstring(value.encode('utf8')) | |
275 return self._array_type.SerializeArray( | |
276 string_array, data_offset, data, handle_offset) | |
277 | |
278 def DeserializePointer(self, size, nb_elements, context): | |
279 string_array = self._array_type.DeserializeArray(size, nb_elements, context) | |
280 return unicode(string_array.tostring(), 'utf8') | |
281 | |
282 | |
283 class BaseHandleType(SerializableType): | |
284 """Type object for handles.""" | |
285 | |
286 def __init__(self, nullable=False, type_code='i'): | |
287 SerializableType.__init__(self, type_code) | |
288 self.nullable = nullable | |
289 | |
290 def Serialize(self, value, data_offset, data, handle_offset): | |
291 handle = self.ToHandle(value) | |
292 if not handle.IsValid() and not self.nullable: | |
293 raise serialization.SerializationException( | |
294 'Trying to serialize null for non nullable type.') | |
295 if not handle.IsValid(): | |
296 return (-1, []) | |
297 return (handle_offset, [handle]) | |
298 | |
299 def Deserialize(self, value, context): | |
300 if value == -1: | |
301 if not self.nullable: | |
302 raise serialization.DeserializationException( | |
303 'Trying to deserialize null for non nullable type.') | |
304 return self.FromHandle(mojo_system.Handle()) | |
305 return self.FromHandle(context.ClaimHandle(value)) | |
306 | |
307 def FromHandle(self, handle): | |
308 raise NotImplementedError() | |
309 | |
310 def ToHandle(self, value): | |
311 raise NotImplementedError() | |
312 | |
313 | |
314 class HandleType(BaseHandleType): | |
315 """Type object for handles.""" | |
316 | |
317 def Convert(self, value): | |
318 if value is None: | |
319 return mojo_system.Handle() | |
320 if not isinstance(value, mojo_system.Handle): | |
321 raise TypeError('%r is not a handle' % value) | |
322 return value | |
323 | |
324 def FromHandle(self, handle): | |
325 return handle | |
326 | |
327 def ToHandle(self, value): | |
328 return value | |
329 | |
330 | |
331 class InterfaceRequestType(BaseHandleType): | |
332 """Type object for interface requests.""" | |
333 | |
334 def Convert(self, value): | |
335 if value is None: | |
336 return reflection.InterfaceRequest(mojo_system.Handle()) | |
337 if not isinstance(value, reflection.InterfaceRequest): | |
338 raise TypeError('%r is not an interface request' % value) | |
339 return value | |
340 | |
341 def FromHandle(self, handle): | |
342 return reflection.InterfaceRequest(handle) | |
343 | |
344 def ToHandle(self, value): | |
345 return value.PassMessagePipe() | |
346 | |
347 | |
348 class InterfaceType(BaseHandleType): | |
349 """Type object for interfaces.""" | |
350 | |
351 def __init__(self, interface_getter, nullable=False): | |
352 # handle (4 bytes) + version (4 bytes) | |
353 BaseHandleType.__init__(self, nullable, 'iI') | |
354 self._interface_getter = interface_getter | |
355 self._interface = None | |
356 | |
357 def Convert(self, value): | |
358 if value is None or isinstance(value, self.interface): | |
359 return value | |
360 raise TypeError('%r is not an instance of ' % self.interface) | |
361 | |
362 @property | |
363 def interface(self): | |
364 if not self._interface: | |
365 self._interface = self._interface_getter() | |
366 return self._interface | |
367 | |
368 def Serialize(self, value, data_offset, data, handle_offset): | |
369 (encoded_handle, handles) = super(InterfaceType, self).Serialize( | |
370 value, data_offset, data, handle_offset) | |
371 if encoded_handle == -1: | |
372 version = 0 | |
373 else: | |
374 version = self.interface.manager.version | |
375 if value and isinstance(value, reflection.InterfaceProxy): | |
376 version = value.manager.version | |
377 return ((encoded_handle, version), handles) | |
378 | |
379 def Deserialize(self, value, context): | |
380 proxy = super(InterfaceType, self).Deserialize(value[0], context) | |
381 if proxy: | |
382 proxy.manager.version = value[1] | |
383 return proxy | |
384 | |
385 def FromHandle(self, handle): | |
386 if handle.IsValid(): | |
387 return self.interface.manager.Proxy(handle) | |
388 return None | |
389 | |
390 def ToHandle(self, value): | |
391 if not value: | |
392 return mojo_system.Handle() | |
393 if isinstance(value, reflection.InterfaceProxy): | |
394 return value.manager.PassMessagePipe() | |
395 pipe = mojo_system.MessagePipe() | |
396 self.interface.manager.Bind(value, pipe.handle0) | |
397 return pipe.handle1 | |
398 | |
399 | |
400 class BaseArrayType(PointerType): | |
401 """Abstract Type object for arrays.""" | |
402 | |
403 def __init__(self, nullable=False, length=0): | |
404 PointerType.__init__(self, nullable) | |
405 self.length = length | |
406 | |
407 def SerializePointer(self, value, data_offset, data, handle_offset): | |
408 if self.length != 0 and len(value) != self.length: | |
409 raise serialization.SerializationException('Incorrect array size') | |
410 return self.SerializeArray(value, data_offset, data, handle_offset) | |
411 | |
412 def SerializeArray(self, value, data_offset, data, handle_offset): | |
413 """Serialize the not null array.""" | |
414 raise NotImplementedError() | |
415 | |
416 def DeserializePointer(self, size, nb_elements, context): | |
417 if self.length != 0 and nb_elements != self.length: | |
418 raise serialization.DeserializationException('Incorrect array size') | |
419 if (size < | |
420 serialization.HEADER_STRUCT.size + self.SizeForLength(nb_elements)): | |
421 raise serialization.DeserializationException('Incorrect array size') | |
422 return self.DeserializeArray(size, nb_elements, context) | |
423 | |
424 def DeserializeArray(self, size, nb_elements, context): | |
425 raise NotImplementedError() | |
426 | |
427 def SizeForLength(self, nb_elements): | |
428 raise NotImplementedError() | |
429 | |
430 | |
431 class BooleanArrayType(BaseArrayType): | |
432 | |
433 def __init__(self, nullable=False, length=0): | |
434 BaseArrayType.__init__(self, nullable, length) | |
435 self._array_type = NativeArrayType('B', nullable) | |
436 | |
437 def Convert(self, value): | |
438 if value is None: | |
439 return value | |
440 return [TYPE_BOOL.Convert(x) for x in value] | |
441 | |
442 def SerializeArray(self, value, data_offset, data, handle_offset): | |
443 groups = [value[i:i+8] for i in range(0, len(value), 8)] | |
444 converted = array.array('B', [_ConvertBooleansToByte(x) for x in groups]) | |
445 return _SerializeNativeArray(converted, data_offset, data, len(value)) | |
446 | |
447 def DeserializeArray(self, size, nb_elements, context): | |
448 converted = self._array_type.DeserializeArray(size, nb_elements, context) | |
449 elements = list(itertools.islice( | |
450 itertools.chain.from_iterable( | |
451 [_ConvertByteToBooleans(x, 8) for x in converted]), | |
452 0, | |
453 nb_elements)) | |
454 return elements | |
455 | |
456 def SizeForLength(self, nb_elements): | |
457 return (nb_elements + 7) // 8 | |
458 | |
459 | |
460 class GenericArrayType(BaseArrayType): | |
461 """Type object for arrays of pointers.""" | |
462 | |
463 def __init__(self, sub_type, nullable=False, length=0): | |
464 BaseArrayType.__init__(self, nullable, length) | |
465 assert isinstance(sub_type, SerializableType) | |
466 self.sub_type = sub_type | |
467 | |
468 def Convert(self, value): | |
469 if value is None: | |
470 return value | |
471 return [self.sub_type.Convert(x) for x in value] | |
472 | |
473 def SerializeArray(self, value, data_offset, data, handle_offset): | |
474 size = (serialization.HEADER_STRUCT.size + | |
475 self.sub_type.GetByteSize() * len(value)) | |
476 data_end = len(data) | |
477 position = len(data) + serialization.HEADER_STRUCT.size | |
478 data.extend(bytearray(size + | |
479 serialization.NeededPaddingForAlignment(size))) | |
480 returned_handles = [] | |
481 to_pack = [] | |
482 for item in value: | |
483 (new_data, new_handles) = self.sub_type.Serialize( | |
484 item, | |
485 len(data) - position, | |
486 data, | |
487 handle_offset + len(returned_handles)) | |
488 to_pack.extend(serialization.Flatten(new_data)) | |
489 returned_handles.extend(new_handles) | |
490 position = position + self.sub_type.GetByteSize() | |
491 | |
492 serialization.HEADER_STRUCT.pack_into(data, data_end, size, len(value)) | |
493 # TODO(azani): Refactor so we don't have to create big formatting strings. | |
494 struct.pack_into(('%s' % self.sub_type.GetTypeCode()) * len(value), | |
495 data, | |
496 data_end + serialization.HEADER_STRUCT.size, | |
497 *to_pack) | |
498 return (data_offset, returned_handles) | |
499 | |
500 def DeserializeArray(self, size, nb_elements, context): | |
501 # TODO(azani): Refactor so the format string isn't so big. | |
502 values = struct.unpack_from( | |
503 nb_elements * self.sub_type.GetTypeCode(), | |
504 buffer(context.data, serialization.HEADER_STRUCT.size)) | |
505 values_per_element = len(self.sub_type.GetTypeCode()) | |
506 assert nb_elements * values_per_element == len(values) | |
507 | |
508 result = [] | |
509 sub_context = context.GetSubContext(serialization.HEADER_STRUCT.size) | |
510 for index in xrange(nb_elements): | |
511 if values_per_element == 1: | |
512 value = values[index] | |
513 else: | |
514 value = tuple(values[index * values_per_element : | |
515 (index + 1) * values_per_element]) | |
516 result.append(self.sub_type.Deserialize( | |
517 value, | |
518 sub_context)) | |
519 sub_context = sub_context.GetSubContext(self.sub_type.GetByteSize()) | |
520 return result | |
521 | |
522 def SizeForLength(self, nb_elements): | |
523 return nb_elements * self.sub_type.GetByteSize(); | |
524 | |
525 | |
526 class NativeArrayType(BaseArrayType): | |
527 """Type object for arrays of native types.""" | |
528 | |
529 def __init__(self, typecode, nullable=False, length=0): | |
530 BaseArrayType.__init__(self, nullable, length) | |
531 self.array_typecode = typecode | |
532 self.element_size = struct.calcsize('<%s' % self.array_typecode) | |
533 | |
534 def Convert(self, value): | |
535 if value is None: | |
536 return value | |
537 if (isinstance(value, array.array) and | |
538 value.array_typecode == self.array_typecode): | |
539 return value | |
540 return array.array(self.array_typecode, value) | |
541 | |
542 def SerializeArray(self, value, data_offset, data, handle_offset): | |
543 return _SerializeNativeArray(value, data_offset, data, len(value)) | |
544 | |
545 def DeserializeArray(self, size, nb_elements, context): | |
546 result = array.array(self.array_typecode) | |
547 result.fromstring(buffer(context.data, | |
548 serialization.HEADER_STRUCT.size, | |
549 size - serialization.HEADER_STRUCT.size)) | |
550 return result | |
551 | |
552 def SizeForLength(self, nb_elements): | |
553 return nb_elements * self.element_size | |
554 | |
555 | |
556 class StructType(PointerType): | |
557 """Type object for structs.""" | |
558 | |
559 def __init__(self, struct_type_getter, nullable=False): | |
560 PointerType.__init__(self) | |
561 self._struct_type_getter = struct_type_getter | |
562 self._struct_type = None | |
563 self.nullable = nullable | |
564 | |
565 @property | |
566 def struct_type(self): | |
567 if not self._struct_type: | |
568 self._struct_type = self._struct_type_getter() | |
569 return self._struct_type | |
570 | |
571 def Convert(self, value): | |
572 if value is None or isinstance(value, self.struct_type): | |
573 return value | |
574 raise TypeError('%r is not an instance of %r' % (value, self.struct_type)) | |
575 | |
576 def GetDefaultValue(self, value): | |
577 if value: | |
578 return self.struct_type() | |
579 return None | |
580 | |
581 def SerializePointer(self, value, data_offset, data, handle_offset): | |
582 (new_data, new_handles) = value.Serialize(handle_offset) | |
583 data.extend(new_data) | |
584 return (data_offset, new_handles) | |
585 | |
586 def DeserializePointer(self, size, nb_elements, context): | |
587 return self.struct_type.Deserialize(context) | |
588 | |
589 | |
590 class MapType(SerializableType): | |
591 """Type objects for maps.""" | |
592 | |
593 def __init__(self, key_type, value_type, nullable=False): | |
594 self._key_type = key_type | |
595 self._value_type = value_type | |
596 dictionary = { | |
597 '__metaclass__': reflection.MojoStructType, | |
598 '__module__': __name__, | |
599 'DESCRIPTOR': { | |
600 'fields': [ | |
601 SingleFieldGroup('keys', MapType._GetArrayType(key_type), 0, 0), | |
602 SingleFieldGroup('values', MapType._GetArrayType(value_type), 1, 0), | |
603 ], | |
604 } | |
605 } | |
606 self.struct = reflection.MojoStructType('MapStruct', (object,), dictionary) | |
607 self.struct_type = StructType(lambda: self.struct, nullable) | |
608 SerializableType.__init__(self, self.struct_type.typecode) | |
609 | |
610 def Convert(self, value): | |
611 if value is None: | |
612 return value | |
613 if isinstance(value, dict): | |
614 return dict([(self._key_type.Convert(x), self._value_type.Convert(y)) for | |
615 x, y in value.iteritems()]) | |
616 raise TypeError('%r is not a dictionary.') | |
617 | |
618 def Serialize(self, value, data_offset, data, handle_offset): | |
619 s = None | |
620 if value is not None: | |
621 keys, values = [], [] | |
622 for key, value in value.iteritems(): | |
623 keys.append(key) | |
624 values.append(value) | |
625 s = self.struct(keys=keys, values=values) | |
626 return self.struct_type.Serialize(s, data_offset, data, handle_offset) | |
627 | |
628 def Deserialize(self, value, context): | |
629 s = self.struct_type.Deserialize(value, context) | |
630 if s: | |
631 if len(s.keys) != len(s.values): | |
632 raise serialization.DeserializationException( | |
633 'keys and values do not have the same length.') | |
634 return dict(zip(s.keys, s.values)) | |
635 return None | |
636 | |
637 @staticmethod | |
638 def _GetArrayType(t): | |
639 if t == TYPE_BOOL: | |
640 return BooleanArrayType() | |
641 else: | |
642 return GenericArrayType(t) | |
643 | |
644 | |
645 TYPE_BOOL = BooleanType('B') | |
646 | |
647 TYPE_INT8 = IntegerType('b') | |
648 TYPE_INT16 = IntegerType('h') | |
649 TYPE_INT32 = IntegerType('i') | |
650 TYPE_INT64 = IntegerType('q') | |
651 | |
652 TYPE_UINT8 = IntegerType('B') | |
653 TYPE_UINT16 = IntegerType('H') | |
654 TYPE_UINT32 = IntegerType('I') | |
655 TYPE_UINT64 = IntegerType('Q') | |
656 | |
657 TYPE_FLOAT = FloatType('f') | |
658 TYPE_DOUBLE = FloatType('d') | |
659 | |
660 TYPE_STRING = StringType() | |
661 TYPE_NULLABLE_STRING = StringType(True) | |
662 | |
663 TYPE_HANDLE = HandleType() | |
664 TYPE_NULLABLE_HANDLE = HandleType(True) | |
665 | |
666 TYPE_INTERFACE_REQUEST = InterfaceRequestType() | |
667 TYPE_NULLABLE_INTERFACE_REQUEST = InterfaceRequestType(True) | |
668 | |
669 | |
670 class FieldDescriptor(object): | |
671 """Describes a field in a generated struct.""" | |
672 | |
673 def __init__(self, name, field_type, index, version, default_value=None): | |
674 self.name = name | |
675 self.field_type = field_type | |
676 self.version = version | |
677 self.index = index | |
678 self._default_value = default_value | |
679 | |
680 def GetDefaultValue(self): | |
681 return self.field_type.GetDefaultValue(self._default_value) | |
682 | |
683 | |
684 class FieldGroup(object): | |
685 """ | |
686 Describe a list of field in the generated struct that must be | |
687 serialized/deserialized together. | |
688 """ | |
689 def __init__(self, descriptors): | |
690 self.descriptors = descriptors | |
691 | |
692 def GetDescriptors(self): | |
693 return self.descriptors | |
694 | |
695 def GetTypeCode(self): | |
696 raise NotImplementedError() | |
697 | |
698 def GetByteSize(self): | |
699 raise NotImplementedError() | |
700 | |
701 def GetAlignment(self): | |
702 raise NotImplementedError() | |
703 | |
704 def GetMinVersion(self): | |
705 raise NotImplementedError() | |
706 | |
707 def GetMaxVersion(self): | |
708 raise NotImplementedError() | |
709 | |
710 def Serialize(self, obj, data_offset, data, handle_offset): | |
711 raise NotImplementedError() | |
712 | |
713 def Deserialize(self, value, context): | |
714 raise NotImplementedError() | |
715 | |
716 def Filter(self, version): | |
717 raise NotImplementedError() | |
718 | |
719 | |
720 class SingleFieldGroup(FieldGroup, FieldDescriptor): | |
721 """A FieldGroup that contains a single FieldDescriptor.""" | |
722 | |
723 def __init__(self, name, field_type, index, version, default_value=None): | |
724 FieldDescriptor.__init__( | |
725 self, name, field_type, index, version, default_value) | |
726 FieldGroup.__init__(self, [self]) | |
727 | |
728 def GetTypeCode(self): | |
729 return self.field_type.GetTypeCode() | |
730 | |
731 def GetByteSize(self): | |
732 return self.field_type.GetByteSize() | |
733 | |
734 def GetAlignment(self): | |
735 return self.field_type.GetAlignment() | |
736 | |
737 def GetMinVersion(self): | |
738 return self.version | |
739 | |
740 def GetMaxVersion(self): | |
741 return self.version | |
742 | |
743 def Serialize(self, obj, data_offset, data, handle_offset): | |
744 value = getattr(obj, self.name) | |
745 return self.field_type.Serialize(value, data_offset, data, handle_offset) | |
746 | |
747 def Deserialize(self, value, context): | |
748 entity = self.field_type.Deserialize(value, context) | |
749 return { self.name: entity } | |
750 | |
751 def Filter(self, version): | |
752 return self | |
753 | |
754 | |
755 class BooleanGroup(FieldGroup): | |
756 """A FieldGroup to pack booleans.""" | |
757 def __init__(self, descriptors): | |
758 FieldGroup.__init__(self, descriptors) | |
759 self.min_version = min([descriptor.version for descriptor in descriptors]) | |
760 self.max_version = max([descriptor.version for descriptor in descriptors]) | |
761 | |
762 def GetTypeCode(self): | |
763 return 'B' | |
764 | |
765 def GetByteSize(self): | |
766 return 1 | |
767 | |
768 def GetAlignment(self): | |
769 return 1 | |
770 | |
771 def GetMinVersion(self): | |
772 return self.min_version | |
773 | |
774 def GetMaxVersion(self): | |
775 return self.max_version | |
776 | |
777 def Serialize(self, obj, data_offset, data, handle_offset): | |
778 value = _ConvertBooleansToByte( | |
779 [getattr(obj, field.name) for field in self.GetDescriptors()]) | |
780 return (value, []) | |
781 | |
782 def Deserialize(self, value, context): | |
783 values = itertools.izip_longest([x.name for x in self.descriptors], | |
784 _ConvertByteToBooleans(value), | |
785 fillvalue=False) | |
786 return dict(values) | |
787 | |
788 def Filter(self, version): | |
789 return BooleanGroup( | |
790 filter(lambda d: d.version <= version, self.descriptors)) | |
791 | |
792 | |
793 def _SerializeNativeArray(value, data_offset, data, length): | |
794 data_size = len(data) | |
795 data.extend(bytearray(serialization.HEADER_STRUCT.size)) | |
796 data.extend(buffer(value)) | |
797 data_length = len(data) - data_size | |
798 data.extend(bytearray(serialization.NeededPaddingForAlignment(data_length))) | |
799 serialization.HEADER_STRUCT.pack_into(data, data_size, data_length, length) | |
800 return (data_offset, []) | |
801 | |
802 | |
803 def _ConvertBooleansToByte(booleans): | |
804 """Pack a list of booleans into an integer.""" | |
805 return reduce(lambda x, y: x * 2 + y, reversed(booleans), 0) | |
806 | |
807 | |
808 def _ConvertByteToBooleans(value, min_size=0): | |
809 """Unpack an integer into a list of booleans.""" | |
810 res = [] | |
811 while value: | |
812 res.append(bool(value&1)) | |
813 value = value / 2 | |
814 res.extend([False] * (min_size - len(res))) | |
815 return res | |
OLD | NEW |