Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(372)

Side by Side Diff: mojo/public/python/mojo_bindings/descriptor.py

Issue 814543006: Move //mojo/{public, edk} underneath //third_party (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
38 class SerializableType(Type):
39 """Describe a type that can be serialized by itself."""
40
41 def __init__(self, typecode):
42 Type.__init__(self)
43 self.typecode = typecode
44 self.byte_size = struct.calcsize('<%s' % self.GetTypeCode())
45
46 def GetTypeCode(self):
47 """
48 Returns the type code (as defined by the struct module) used to encode
49 this type.
50 """
51 return self.typecode
52
53 def GetByteSize(self):
54 """
55 Returns the size of the encoding of this type.
56 """
57 return self.byte_size
58
59 def Serialize(self, value, data_offset, data, handle_offset):
60 """
61 Serialize a value of this type.
62
63 Args:
64 value: the value to serialize.
65 data_offset: the offset to the end of the data bytearray. Used to encode
66 pointers.
67 data: the bytearray to append additional data to.
68 handle_offset: the offset to use to encode handles.
69
70 Returns a a tuple where the first element is the value to encode, and the
71 second is the array of handles to add to the message.
72 """
73 raise NotImplementedError()
74
75 def Deserialize(self, value, context):
76 """
77 Deserialize a value of this type.
78
79 Args:
80 value: the base value for this type. This is always a numeric type, and
81 corresponds to the first element in the tuple returned by
82 Serialize.
83 data: the bytearray to retrieve additional data from.
84 handles: the array of handles contained in the message to deserialize.
85
86 Returns the deserialized value.
87 """
88 raise NotImplementedError()
89
90
91 class BooleanType(Type):
92 """Type object for booleans"""
93
94 def Convert(self, value):
95 return bool(value)
96
97
98 class NumericType(SerializableType):
99 """Base Type object for all numeric types"""
100
101 def GetDefaultValue(self, value):
102 if value is None:
103 return self.Convert(0)
104 return self.Convert(value)
105
106 def Serialize(self, value, data_offset, data, handle_offset):
107 return (value, [])
108
109 def Deserialize(self, value, context):
110 return value
111
112
113 class IntegerType(NumericType):
114 """Type object for integer types."""
115
116 def __init__(self, typecode):
117 NumericType.__init__(self, typecode)
118 size = 8 * self.byte_size
119 signed = typecode.islower()
120 if signed:
121 self._min_value = -(1 << (size - 1))
122 self._max_value = (1 << (size - 1)) - 1
123 else:
124 self._min_value = 0
125 self._max_value = (1 << size) - 1
126
127 def Convert(self, value):
128 if value is None:
129 raise TypeError('None is not an integer.')
130 if not isinstance(value, (int, long)):
131 raise TypeError('%r is not an integer type' % value)
132 if value < self._min_value or value > self._max_value:
133 raise OverflowError('%r is not in the range [%d, %d]' %
134 (value, self._min_value, self._max_value))
135 return value
136
137
138 class FloatType(NumericType):
139 """Type object for floating point number types."""
140
141 def Convert(self, value):
142 if value is None:
143 raise TypeError('None is not an floating point number.')
144 if not isinstance(value, (int, long, float)):
145 raise TypeError('%r is not a numeric type' % value)
146 return float(value)
147
148
149 class PointerType(SerializableType):
150 """Base Type object for pointers."""
151
152 def __init__(self, nullable=False):
153 SerializableType.__init__(self, 'Q')
154 self.nullable = nullable
155
156 def Serialize(self, value, data_offset, data, handle_offset):
157 if value is None and not self.nullable:
158 raise serialization.SerializationException(
159 'Trying to serialize null for non nullable type.')
160 if value is None:
161 return (0, [])
162 return self.SerializePointer(value, data_offset, data, handle_offset)
163
164 def Deserialize(self, value, context):
165 if value == 0:
166 if not self.nullable:
167 raise serialization.DeserializationException(
168 'Trying to deserialize null for non nullable type.')
169 return None
170 if value % 8 != 0:
171 raise serialization.DeserializationException(
172 'Pointer alignment is incorrect.')
173 sub_context = context.GetSubContext(value)
174 if len(sub_context.data) < serialization.HEADER_STRUCT.size:
175 raise serialization.DeserializationException(
176 'Available data too short to contain header.')
177 (size, nb_elements) = serialization.HEADER_STRUCT.unpack_from(
178 sub_context.data)
179 if len(sub_context.data) < size or size < serialization.HEADER_STRUCT.size:
180 raise serialization.DeserializationException('Header size is incorrect.')
181 sub_context.ClaimMemory(0, size)
182 return self.DeserializePointer(size, nb_elements, sub_context)
183
184 def SerializePointer(self, value, data_offset, data, handle_offset):
185 """Serialize the not null value."""
186 raise NotImplementedError()
187
188 def DeserializePointer(self, size, nb_elements, context):
189 raise NotImplementedError()
190
191
192 class StringType(PointerType):
193 """
194 Type object for strings.
195
196 Strings are represented as unicode, and the conversion is done using the
197 default encoding if a string instance is used.
198 """
199
200 def __init__(self, nullable=False):
201 PointerType.__init__(self, nullable)
202 self._array_type = NativeArrayType('B', nullable)
203
204 def Convert(self, value):
205 if value is None or isinstance(value, unicode):
206 return value
207 if isinstance(value, str):
208 return unicode(value)
209 raise TypeError('%r is not a string' % value)
210
211 def SerializePointer(self, value, data_offset, data, handle_offset):
212 string_array = array.array('b')
213 string_array.fromstring(value.encode('utf8'))
214 return self._array_type.SerializeArray(
215 string_array, data_offset, data, handle_offset)
216
217 def DeserializePointer(self, size, nb_elements, context):
218 string_array = self._array_type.DeserializeArray(size, nb_elements, context)
219 return unicode(string_array.tostring(), 'utf8')
220
221
222 class BaseHandleType(SerializableType):
223 """Type object for handles."""
224
225 def __init__(self, nullable=False):
226 SerializableType.__init__(self, 'i')
227 self.nullable = nullable
228
229 def Serialize(self, value, data_offset, data, handle_offset):
230 handle = self.ToHandle(value)
231 if not handle.IsValid() and not self.nullable:
232 raise serialization.SerializationException(
233 'Trying to serialize null for non nullable type.')
234 if not handle.IsValid():
235 return (-1, [])
236 return (handle_offset, [handle])
237
238 def Deserialize(self, value, context):
239 if value == -1:
240 if not self.nullable:
241 raise serialization.DeserializationException(
242 'Trying to deserialize null for non nullable type.')
243 return self.FromHandle(mojo_system.Handle())
244 return self.FromHandle(context.ClaimHandle(value))
245
246 def FromHandle(self, handle):
247 raise NotImplementedError()
248
249 def ToHandle(self, value):
250 raise NotImplementedError()
251
252
253 class HandleType(BaseHandleType):
254 """Type object for handles."""
255
256 def Convert(self, value):
257 if value is None:
258 return mojo_system.Handle()
259 if not isinstance(value, mojo_system.Handle):
260 raise TypeError('%r is not a handle' % value)
261 return value
262
263 def FromHandle(self, handle):
264 return handle
265
266 def ToHandle(self, value):
267 return value
268
269
270 class InterfaceRequestType(BaseHandleType):
271 """Type object for interface requests."""
272
273 def Convert(self, value):
274 if value is None:
275 return reflection.InterfaceRequest(mojo_system.Handle())
276 if not isinstance(value, reflection.InterfaceRequest):
277 raise TypeError('%r is not an interface request' % value)
278 return value
279
280 def FromHandle(self, handle):
281 return reflection.InterfaceRequest(handle)
282
283 def ToHandle(self, value):
284 return value.PassMessagePipe()
285
286
287 class InterfaceType(BaseHandleType):
288 """Type object for interfaces."""
289
290 def __init__(self, interface_getter, nullable=False):
291 BaseHandleType.__init__(self, nullable)
292 self._interface_getter = interface_getter
293 self._interface = None
294
295 def Convert(self, value):
296 if value is None or isinstance(value, self.interface):
297 return value
298 raise TypeError('%r is not an instance of ' % self.interface)
299
300 @property
301 def interface(self):
302 if not self._interface:
303 self._interface = self._interface_getter()
304 return self._interface
305
306 def FromHandle(self, handle):
307 if handle.IsValid():
308 return self.interface.manager.Proxy(handle)
309 return None
310
311 def ToHandle(self, value):
312 if not value:
313 return mojo_system.Handle()
314 if isinstance(value, reflection.InterfaceProxy):
315 return value.manager.PassMessagePipe()
316 pipe = mojo_system.MessagePipe()
317 self.interface.manager.Bind(value, pipe.handle0)
318 return pipe.handle1
319
320
321 class BaseArrayType(PointerType):
322 """Abstract Type object for arrays."""
323
324 def __init__(self, nullable=False, length=0):
325 PointerType.__init__(self, nullable)
326 self.length = length
327
328 def SerializePointer(self, value, data_offset, data, handle_offset):
329 if self.length != 0 and len(value) != self.length:
330 raise serialization.SerializationException('Incorrect array size')
331 return self.SerializeArray(value, data_offset, data, handle_offset)
332
333 def SerializeArray(self, value, data_offset, data, handle_offset):
334 """Serialize the not null array."""
335 raise NotImplementedError()
336
337 def DeserializePointer(self, size, nb_elements, context):
338 if self.length != 0 and nb_elements != self.length:
339 raise serialization.DeserializationException('Incorrect array size')
340 if (size <
341 serialization.HEADER_STRUCT.size + self.SizeForLength(nb_elements)):
342 raise serialization.DeserializationException('Incorrect array size')
343 return self.DeserializeArray(size, nb_elements, context)
344
345 def DeserializeArray(self, size, nb_elements, context):
346 raise NotImplementedError()
347
348 def SizeForLength(self, nb_elements):
349 raise NotImplementedError()
350
351
352 class BooleanArrayType(BaseArrayType):
353
354 def __init__(self, nullable=False, length=0):
355 BaseArrayType.__init__(self, nullable, length)
356 self._array_type = NativeArrayType('B', nullable)
357
358 def Convert(self, value):
359 if value is None:
360 return value
361 return [TYPE_BOOL.Convert(x) for x in value]
362
363 def SerializeArray(self, value, data_offset, data, handle_offset):
364 groups = [value[i:i+8] for i in range(0, len(value), 8)]
365 converted = array.array('B', [_ConvertBooleansToByte(x) for x in groups])
366 return _SerializeNativeArray(converted, data_offset, data, len(value))
367
368 def DeserializeArray(self, size, nb_elements, context):
369 converted = self._array_type.DeserializeArray(size, nb_elements, context)
370 elements = list(itertools.islice(
371 itertools.chain.from_iterable(
372 [_ConvertByteToBooleans(x, 8) for x in converted]),
373 0,
374 nb_elements))
375 return elements
376
377 def SizeForLength(self, nb_elements):
378 return (nb_elements + 7) // 8
379
380
381 class GenericArrayType(BaseArrayType):
382 """Type object for arrays of pointers."""
383
384 def __init__(self, sub_type, nullable=False, length=0):
385 BaseArrayType.__init__(self, nullable, length)
386 assert isinstance(sub_type, SerializableType)
387 self.sub_type = sub_type
388
389 def Convert(self, value):
390 if value is None:
391 return value
392 return [self.sub_type.Convert(x) for x in value]
393
394 def SerializeArray(self, value, data_offset, data, handle_offset):
395 size = (serialization.HEADER_STRUCT.size +
396 self.sub_type.GetByteSize() * len(value))
397 data_end = len(data)
398 position = len(data) + serialization.HEADER_STRUCT.size
399 data.extend(bytearray(size +
400 serialization.NeededPaddingForAlignment(size)))
401 returned_handles = []
402 to_pack = []
403 for item in value:
404 (new_data, new_handles) = self.sub_type.Serialize(
405 item,
406 len(data) - position,
407 data,
408 handle_offset + len(returned_handles))
409 to_pack.append(new_data)
410 returned_handles.extend(new_handles)
411 position = position + self.sub_type.GetByteSize()
412 serialization.HEADER_STRUCT.pack_into(data, data_end, size, len(value))
413 struct.pack_into('%d%s' % (len(value), self.sub_type.GetTypeCode()),
414 data,
415 data_end + serialization.HEADER_STRUCT.size,
416 *to_pack)
417 return (data_offset, returned_handles)
418
419 def DeserializeArray(self, size, nb_elements, context):
420 values = struct.unpack_from(
421 '%d%s' % (nb_elements, self.sub_type.GetTypeCode()),
422 buffer(context.data, serialization.HEADER_STRUCT.size))
423 result = []
424 sub_context = context.GetSubContext(serialization.HEADER_STRUCT.size)
425 for value in values:
426 result.append(self.sub_type.Deserialize(
427 value,
428 sub_context))
429 sub_context = sub_context.GetSubContext(self.sub_type.GetByteSize())
430 return result
431
432 def SizeForLength(self, nb_elements):
433 return nb_elements * self.sub_type.GetByteSize();
434
435
436 class NativeArrayType(BaseArrayType):
437 """Type object for arrays of native types."""
438
439 def __init__(self, typecode, nullable=False, length=0):
440 BaseArrayType.__init__(self, nullable, length)
441 self.array_typecode = typecode
442 self.element_size = struct.calcsize('<%s' % self.array_typecode)
443
444 def Convert(self, value):
445 if value is None:
446 return value
447 if (isinstance(value, array.array) and
448 value.array_typecode == self.array_typecode):
449 return value
450 return array.array(self.array_typecode, value)
451
452 def SerializeArray(self, value, data_offset, data, handle_offset):
453 return _SerializeNativeArray(value, data_offset, data, len(value))
454
455 def DeserializeArray(self, size, nb_elements, context):
456 result = array.array(self.array_typecode)
457 result.fromstring(buffer(context.data,
458 serialization.HEADER_STRUCT.size,
459 size - serialization.HEADER_STRUCT.size))
460 return result
461
462 def SizeForLength(self, nb_elements):
463 return nb_elements * self.element_size
464
465
466 class StructType(PointerType):
467 """Type object for structs."""
468
469 def __init__(self, struct_type_getter, nullable=False):
470 PointerType.__init__(self)
471 self._struct_type_getter = struct_type_getter
472 self._struct_type = None
473 self.nullable = nullable
474
475 @property
476 def struct_type(self):
477 if not self._struct_type:
478 self._struct_type = self._struct_type_getter()
479 return self._struct_type
480
481 def Convert(self, value):
482 if value is None or isinstance(value, self.struct_type):
483 return value
484 raise TypeError('%r is not an instance of %r' % (value, self.struct_type))
485
486 def GetDefaultValue(self, value):
487 if value:
488 return self.struct_type()
489 return None
490
491 def SerializePointer(self, value, data_offset, data, handle_offset):
492 (new_data, new_handles) = value.Serialize(handle_offset)
493 data.extend(new_data)
494 return (data_offset, new_handles)
495
496 def DeserializePointer(self, size, nb_elements, context):
497 return self.struct_type.Deserialize(context)
498
499
500 class MapType(SerializableType):
501 """Type objects for maps."""
502
503 def __init__(self, key_type, value_type, nullable=False):
504 self._key_type = key_type
505 self._value_type = value_type
506 dictionary = {
507 '__metaclass__': reflection.MojoStructType,
508 '__module__': __name__,
509 'DESCRIPTOR': {
510 'fields': [
511 SingleFieldGroup('keys', MapType._GetArrayType(key_type), 0, 0),
512 SingleFieldGroup('values', MapType._GetArrayType(value_type), 1, 1),
513 ],
514 }
515 }
516 self.struct = reflection.MojoStructType('MapStruct', (object,), dictionary)
517 self.struct_type = StructType(lambda: self.struct, nullable)
518 SerializableType.__init__(self, self.struct_type.typecode)
519
520 def Convert(self, value):
521 if value is None:
522 return value
523 if isinstance(value, dict):
524 return dict([(self._key_type.Convert(x), self._value_type.Convert(y)) for
525 x, y in value.iteritems()])
526 raise TypeError('%r is not a dictionary.')
527
528 def Serialize(self, value, data_offset, data, handle_offset):
529 s = None
530 if value:
531 keys, values = [], []
532 for key, value in value.iteritems():
533 keys.append(key)
534 values.append(value)
535 s = self.struct(keys=keys, values=values)
536 return self.struct_type.Serialize(s, data_offset, data, handle_offset)
537
538 def Deserialize(self, value, context):
539 s = self.struct_type.Deserialize(value, context)
540 if s:
541 if len(s.keys) != len(s.values):
542 raise serialization.DeserializationException(
543 'keys and values do not have the same length.')
544 return dict(zip(s.keys, s.values))
545 return None
546
547 @staticmethod
548 def _GetArrayType(t):
549 if t == TYPE_BOOL:
550 return BooleanArrayType()
551 else:
552 return GenericArrayType(t)
553
554
555 TYPE_BOOL = BooleanType()
556
557 TYPE_INT8 = IntegerType('b')
558 TYPE_INT16 = IntegerType('h')
559 TYPE_INT32 = IntegerType('i')
560 TYPE_INT64 = IntegerType('q')
561
562 TYPE_UINT8 = IntegerType('B')
563 TYPE_UINT16 = IntegerType('H')
564 TYPE_UINT32 = IntegerType('I')
565 TYPE_UINT64 = IntegerType('Q')
566
567 TYPE_FLOAT = FloatType('f')
568 TYPE_DOUBLE = FloatType('d')
569
570 TYPE_STRING = StringType()
571 TYPE_NULLABLE_STRING = StringType(True)
572
573 TYPE_HANDLE = HandleType()
574 TYPE_NULLABLE_HANDLE = HandleType(True)
575
576 TYPE_INTERFACE_REQUEST = InterfaceRequestType()
577 TYPE_NULLABLE_INTERFACE_REQUEST = InterfaceRequestType(True)
578
579
580 class FieldDescriptor(object):
581 """Describes a field in a generated struct."""
582
583 def __init__(self, name, field_type, index, version, default_value=None):
584 self.name = name
585 self.field_type = field_type
586 self.version = version
587 self.index = index
588 self._default_value = default_value
589
590 def GetDefaultValue(self):
591 return self.field_type.GetDefaultValue(self._default_value)
592
593
594 class FieldGroup(object):
595 """
596 Describe a list of field in the generated struct that must be
597 serialized/deserialized together.
598 """
599 def __init__(self, descriptors):
600 self.descriptors = descriptors
601
602 def GetDescriptors(self):
603 return self.descriptors
604
605 def GetTypeCode(self):
606 raise NotImplementedError()
607
608 def GetByteSize(self):
609 raise NotImplementedError()
610
611 def GetVersion(self):
612 raise NotImplementedError()
613
614 def Serialize(self, obj, data_offset, data, handle_offset):
615 raise NotImplementedError()
616
617 def Deserialize(self, value, context):
618 raise NotImplementedError()
619
620
621 class SingleFieldGroup(FieldGroup, FieldDescriptor):
622 """A FieldGroup that contains a single FieldDescriptor."""
623
624 def __init__(self, name, field_type, index, version, default_value=None):
625 FieldDescriptor.__init__(
626 self, name, field_type, index, version, default_value)
627 FieldGroup.__init__(self, [self])
628
629 def GetTypeCode(self):
630 return self.field_type.GetTypeCode()
631
632 def GetByteSize(self):
633 return self.field_type.GetByteSize()
634
635 def GetVersion(self):
636 return self.version
637
638 def Serialize(self, obj, data_offset, data, handle_offset):
639 value = getattr(obj, self.name)
640 return self.field_type.Serialize(value, data_offset, data, handle_offset)
641
642 def Deserialize(self, value, context):
643 entity = self.field_type.Deserialize(value, context)
644 return { self.name: entity }
645
646
647 class BooleanGroup(FieldGroup):
648 """A FieldGroup to pack booleans."""
649 def __init__(self, descriptors):
650 FieldGroup.__init__(self, descriptors)
651 self.version = min([descriptor.version for descriptor in descriptors])
652
653 def GetTypeCode(self):
654 return 'B'
655
656 def GetByteSize(self):
657 return 1
658
659 def GetVersion(self):
660 return self.version
661
662 def Serialize(self, obj, data_offset, data, handle_offset):
663 value = _ConvertBooleansToByte(
664 [getattr(obj, field.name) for field in self.GetDescriptors()])
665 return (value, [])
666
667 def Deserialize(self, value, context):
668 values = itertools.izip_longest([x.name for x in self.descriptors],
669 _ConvertByteToBooleans(value),
670 fillvalue=False)
671 return dict(values)
672
673
674 def _SerializeNativeArray(value, data_offset, data, length):
675 data_size = len(data)
676 data.extend(bytearray(serialization.HEADER_STRUCT.size))
677 data.extend(buffer(value))
678 data_length = len(data) - data_size
679 data.extend(bytearray(serialization.NeededPaddingForAlignment(data_length)))
680 serialization.HEADER_STRUCT.pack_into(data, data_size, data_length, length)
681 return (data_offset, [])
682
683
684 def _ConvertBooleansToByte(booleans):
685 """Pack a list of booleans into an integer."""
686 return reduce(lambda x, y: x * 2 + y, reversed(booleans), 0)
687
688
689 def _ConvertByteToBooleans(value, min_size=0):
690 """Unpack an integer into a list of booleans."""
691 res = []
692 while value:
693 res.append(bool(value&1))
694 value = value / 2
695 res.extend([False] * (min_size - len(res)))
696 return res
OLDNEW
« no previous file with comments | « mojo/public/python/mojo_bindings/__init__.py ('k') | mojo/public/python/mojo_bindings/messaging.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698