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.
6 The descriptors used to define generated elements of the mojo python bindings.
13 import mojo.bindings.reflection as reflection
14 import mojo.bindings.serialization as serialization
16 # pylint: disable=E0611,F0401
21 """Describes the type of a struct field or a method parameter,"""
23 def Convert(self, value): # pylint: disable=R0201
25 Convert the given value into its canonical representation, raising an
26 exception if the value cannot be converted.
30 def GetDefaultValue(self, value):
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.
35 return self.Convert(value)
38 class SerializableType(Type):
39 """Describe a type that can be serialized by itself."""
41 def __init__(self, typecode):
43 self.typecode = typecode
44 self.byte_size = struct.calcsize('=%s' % self.GetTypeCode())
46 def GetTypeCode(self):
48 Returns the type code (as defined by the struct module) used to encode
53 def GetByteSize(self):
55 Returns the size of the encoding of this type.
59 def Serialize(self, value, data_offset, data, handle_offset):
61 Serialize a value of this type.
64 value: the value to serialize.
65 data_offset: the offset to the end of the data bytearray. Used to encode
67 data: the bytearray to append additional data to.
68 handle_offset: the offset to use to encode handles.
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.
73 raise NotImplementedError()
75 def Deserialize(self, value, data, handles):
77 Deserialize a value of this type.
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
83 data: the bytearray to retrieve additional data from.
84 handles: the array of handles contained in the message to deserialize.
86 Returns the deserialized value.
88 raise NotImplementedError()
91 class BooleanType(Type):
92 """Type object for booleans"""
94 def Convert(self, value):
98 class NumericType(SerializableType):
99 """Base Type object for all numeric types"""
101 def GetDefaultValue(self, value):
103 return self.Convert(0)
104 return self.Convert(value)
106 def Serialize(self, value, data_offset, data, handle_offset):
109 def Deserialize(self, value, data, handles):
113 class IntegerType(NumericType):
114 """Type object for integer types."""
116 def __init__(self, typecode):
117 NumericType.__init__(self, typecode)
118 size = 8 * self.byte_size
119 signed = typecode.islower()
121 self._min_value = -(1 << (size - 1))
122 self._max_value = (1 << (size - 1)) - 1
125 self._max_value = (1 << size) - 1
127 def Convert(self, value):
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))
138 class FloatType(NumericType):
139 """Type object for floating point number types."""
141 def Convert(self, value):
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)
149 class PointerType(SerializableType):
150 """Base Type object for pointers."""
152 def __init__(self, nullable=False):
153 SerializableType.__init__(self, 'Q')
154 self.nullable = nullable
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.')
162 return self.SerializePointer(value, data_offset, data, handle_offset)
164 def Deserialize(self, value, data, handles):
166 if not self.nullable:
167 raise serialization.DeserializationException(
168 'Trying to deserialize null for non nullable type.')
170 pointed_data = buffer(data, value)
171 (size, nb_elements) = serialization.HEADER_STRUCT.unpack_from(pointed_data)
172 return self.DeserializePointer(size, nb_elements, pointed_data, handles)
174 def SerializePointer(self, value, data_offset, data, handle_offset):
175 """Serialize the not null value."""
176 raise NotImplementedError()
178 def DeserializePointer(self, size, nb_elements, data, handles):
179 raise NotImplementedError()
182 class StringType(PointerType):
184 Type object for strings.
186 Strings are represented as unicode, and the conversion is done using the
187 default encoding if a string instance is used.
190 def __init__(self, nullable=False):
191 PointerType.__init__(self, nullable)
192 self._array_type = NativeArrayType('B', nullable)
194 def Convert(self, value):
195 if value is None or isinstance(value, unicode):
197 if isinstance(value, str):
198 return unicode(value)
199 raise TypeError('%r is not a string' % value)
201 def SerializePointer(self, value, data_offset, data, handle_offset):
202 string_array = array.array('b')
203 string_array.fromstring(value.encode('utf8'))
204 return self._array_type.SerializeArray(
205 string_array, data_offset, data, handle_offset)
207 def DeserializePointer(self, size, nb_elements, data, handles):
208 string_array = self._array_type.DeserializeArray(
209 size, nb_elements, data, handles)
210 return unicode(string_array.tostring(), 'utf8')
213 class BaseHandleType(SerializableType):
214 """Type object for handles."""
216 def __init__(self, nullable=False):
217 SerializableType.__init__(self, 'i')
218 self.nullable = nullable
220 def Serialize(self, value, data_offset, data, handle_offset):
221 handle = self.ToHandle(value)
222 if not handle.IsValid() and not self.nullable:
223 raise serialization.SerializationException(
224 'Trying to serialize null for non nullable type.')
225 if not handle.IsValid():
227 return (handle_offset, [handle])
229 def Deserialize(self, value, data, handles):
231 if not self.nullable:
232 raise serialization.DeserializationException(
233 'Trying to deserialize null for non nullable type.')
234 return self.FromHandle(mojo.system.Handle())
235 # TODO(qsr) validate handle order
236 return self.FromHandle(handles[value])
238 def FromHandle(self, handle):
239 raise NotImplementedError()
241 def ToHandle(self, value):
242 raise NotImplementedError()
245 class HandleType(BaseHandleType):
246 """Type object for handles."""
248 def Convert(self, value):
250 return mojo.system.Handle()
251 if not isinstance(value, mojo.system.Handle):
252 raise TypeError('%r is not a handle' % value)
255 def FromHandle(self, handle):
258 def ToHandle(self, value):
262 class InterfaceRequestType(BaseHandleType):
263 """Type object for interface requests."""
265 def Convert(self, value):
267 return reflection.InterfaceRequest(mojo.system.Handle())
268 if not isinstance(value, reflection.InterfaceRequest):
269 raise TypeError('%r is not an interface request' % value)
272 def FromHandle(self, handle):
273 return reflection.InterfaceRequest(handle)
275 def ToHandle(self, value):
276 return value.PassMessagePipe()
279 class InterfaceType(BaseHandleType):
280 """Type object for interfaces."""
282 def __init__(self, interface_getter, nullable=False):
283 BaseHandleType.__init__(self, nullable)
284 self._interface_getter = interface_getter
285 self._interface = None
287 def Convert(self, value):
288 if value is None or isinstance(value, self.interface):
290 raise TypeError('%r is not an instance of ' % self.interface)
294 if not self._interface:
295 self._interface = self._interface_getter()
296 return self._interface
298 def FromHandle(self, handle):
300 return self.interface.manager.Proxy(handle)
303 def ToHandle(self, value):
305 return mojo.system.Handle()
306 if isinstance(value, reflection.InterfaceProxy):
307 return value.manager.PassMessagePipe()
308 pipe = mojo.system.MessagePipe()
309 self.interface.manager.Bind(value, pipe.handle0)
313 class BaseArrayType(PointerType):
314 """Abstract Type object for arrays."""
316 def __init__(self, nullable=False, length=0):
317 PointerType.__init__(self, nullable)
320 def SerializePointer(self, value, data_offset, data, handle_offset):
321 if self.length != 0 and len(value) != self.length:
322 raise serialization.SerializationException('Incorrect array size')
323 return self.SerializeArray(value, data_offset, data, handle_offset)
325 def SerializeArray(self, value, data_offset, data, handle_offset):
326 """Serialize the not null array."""
327 raise NotImplementedError()
329 def DeserializePointer(self, size, nb_elements, data, handles):
330 if self.length != 0 and size != self.length:
331 raise serialization.DeserializationException('Incorrect array size')
332 return self.DeserializeArray(size, nb_elements, data, handles)
334 def DeserializeArray(self, size, nb_elements, data, handles):
335 raise NotImplementedError()
338 class BooleanArrayType(BaseArrayType):
340 def __init__(self, nullable=False, length=0):
341 BaseArrayType.__init__(self, nullable, length)
342 self._array_type = NativeArrayType('B', nullable)
344 def Convert(self, value):
347 return [TYPE_BOOL.Convert(x) for x in value]
349 def SerializeArray(self, value, data_offset, data, handle_offset):
350 groups = [value[i:i+8] for i in range(0, len(value), 8)]
351 converted = array.array('B', [_ConvertBooleansToByte(x) for x in groups])
352 return _SerializeNativeArray(converted, data_offset, data, len(value))
354 def DeserializeArray(self, size, nb_elements, data, handles):
355 converted = self._array_type.DeserializeArray(
356 size, nb_elements, data, handles)
357 elements = list(itertools.islice(
358 itertools.chain.from_iterable(
359 [_ConvertByteToBooleans(x, 8) for x in converted]),
365 class GenericArrayType(BaseArrayType):
366 """Type object for arrays of pointers."""
368 def __init__(self, sub_type, nullable=False, length=0):
369 BaseArrayType.__init__(self, nullable, length)
370 assert isinstance(sub_type, SerializableType)
371 self.sub_type = sub_type
373 def Convert(self, value):
376 return [self.sub_type.Convert(x) for x in value]
378 def SerializeArray(self, value, data_offset, data, handle_offset):
379 size = (serialization.HEADER_STRUCT.size +
380 self.sub_type.GetByteSize() * len(value))
382 position = len(data) + serialization.HEADER_STRUCT.size
383 data.extend(bytearray(size +
384 serialization.NeededPaddingForAlignment(size)))
385 returned_handles = []
388 (new_data, new_handles) = self.sub_type.Serialize(
390 len(data) - position,
392 handle_offset + len(returned_handles))
393 to_pack.append(new_data)
394 returned_handles.extend(new_handles)
395 position = position + self.sub_type.GetByteSize()
396 serialization.HEADER_STRUCT.pack_into(data, data_end, size, len(value))
397 struct.pack_into('%d%s' % (len(value), self.sub_type.GetTypeCode()),
399 data_end + serialization.HEADER_STRUCT.size,
401 return (data_offset, returned_handles)
403 def DeserializeArray(self, size, nb_elements, data, handles):
404 values = struct.unpack_from(
405 '%d%s' % (nb_elements, self.sub_type.GetTypeCode()),
406 buffer(data, serialization.HEADER_STRUCT.size))
408 position = serialization.HEADER_STRUCT.size
411 self.sub_type.Deserialize(value, buffer(data, position), handles))
412 position += self.sub_type.GetByteSize()
416 class NativeArrayType(BaseArrayType):
417 """Type object for arrays of native types."""
419 def __init__(self, typecode, nullable=False, length=0):
420 BaseArrayType.__init__(self, nullable, length)
421 self.array_typecode = typecode
423 def Convert(self, value):
426 if (isinstance(value, array.array) and
427 value.array_typecode == self.array_typecode):
429 return array.array(self.array_typecode, value)
431 def SerializeArray(self, value, data_offset, data, handle_offset):
432 return _SerializeNativeArray(value, data_offset, data, len(value))
434 def DeserializeArray(self, size, nb_elements, data, handles):
435 result = array.array(self.array_typecode)
436 result.fromstring(buffer(data,
437 serialization.HEADER_STRUCT.size,
438 size - serialization.HEADER_STRUCT.size))
442 class StructType(PointerType):
443 """Type object for structs."""
445 def __init__(self, struct_type_getter, nullable=False):
446 PointerType.__init__(self)
447 self._struct_type_getter = struct_type_getter
448 self._struct_type = None
449 self.nullable = nullable
452 def struct_type(self):
453 if not self._struct_type:
454 self._struct_type = self._struct_type_getter()
455 return self._struct_type
457 def Convert(self, value):
458 if value is None or isinstance(value, self.struct_type):
460 raise TypeError('%r is not an instance of %r' % (value, self.struct_type))
462 def GetDefaultValue(self, value):
464 return self.struct_type()
467 def SerializePointer(self, value, data_offset, data, handle_offset):
468 (new_data, new_handles) = value.Serialize(handle_offset)
469 data.extend(new_data)
470 return (data_offset, new_handles)
472 def DeserializePointer(self, size, nb_elements, data, handles):
473 return self.struct_type.Deserialize(data, handles)
476 class MapType(SerializableType):
477 """Type objects for maps."""
479 def __init__(self, key_type, value_type, nullable=False):
480 self._key_type = key_type
481 self._value_type = value_type
483 '__metaclass__': reflection.MojoStructType,
484 '__module__': __name__,
487 SingleFieldGroup('keys', MapType._GetArrayType(key_type), 0, 0),
488 SingleFieldGroup('values', MapType._GetArrayType(value_type), 1, 1),
492 self.struct = reflection.MojoStructType('MapStruct', (object,), dictionary)
493 self.struct_type = StructType(lambda: self.struct, nullable)
494 SerializableType.__init__(self, self.struct_type.typecode)
496 def Convert(self, value):
499 if isinstance(value, dict):
500 return dict([(self._key_type.Convert(x), self._value_type.Convert(y)) for
501 x, y in value.iteritems()])
502 raise TypeError('%r is not a dictionary.')
504 def Serialize(self, value, data_offset, data, handle_offset):
507 keys, values = [], []
508 for key, value in value.iteritems():
511 s = self.struct(keys=keys, values=values)
512 return self.struct_type.Serialize(s, data_offset, data, handle_offset)
514 def Deserialize(self, value, data, handles):
515 s = self.struct_type.Deserialize(value, data, handles)
517 if len(s.keys) != len(s.values):
518 raise serialization.DeserializationException(
519 'keys and values do not have the same length.')
520 return dict(zip(s.keys, s.values))
524 def _GetArrayType(t):
526 return BooleanArrayType()
528 return GenericArrayType(t)
531 TYPE_BOOL = BooleanType()
533 TYPE_INT8 = IntegerType('b')
534 TYPE_INT16 = IntegerType('h')
535 TYPE_INT32 = IntegerType('i')
536 TYPE_INT64 = IntegerType('q')
538 TYPE_UINT8 = IntegerType('B')
539 TYPE_UINT16 = IntegerType('H')
540 TYPE_UINT32 = IntegerType('I')
541 TYPE_UINT64 = IntegerType('Q')
543 TYPE_FLOAT = FloatType('f')
544 TYPE_DOUBLE = FloatType('d')
546 TYPE_STRING = StringType()
547 TYPE_NULLABLE_STRING = StringType(True)
549 TYPE_HANDLE = HandleType()
550 TYPE_NULLABLE_HANDLE = HandleType(True)
552 TYPE_INTERFACE_REQUEST = InterfaceRequestType()
553 TYPE_NULLABLE_INTERFACE_REQUEST = InterfaceRequestType(True)
556 class FieldDescriptor(object):
557 """Describes a field in a generated struct."""
559 def __init__(self, name, field_type, index, version, default_value=None):
561 self.field_type = field_type
562 self.version = version
564 self._default_value = default_value
566 def GetDefaultValue(self):
567 return self.field_type.GetDefaultValue(self._default_value)
570 class FieldGroup(object):
572 Describe a list of field in the generated struct that must be
573 serialized/deserialized together.
575 def __init__(self, descriptors):
576 self.descriptors = descriptors
578 def GetDescriptors(self):
579 return self.descriptors
581 def GetTypeCode(self):
582 raise NotImplementedError()
584 def GetByteSize(self):
585 raise NotImplementedError()
587 def GetVersion(self):
588 raise NotImplementedError()
590 def Serialize(self, obj, data_offset, data, handle_offset):
591 raise NotImplementedError()
593 def Deserialize(self, value, data, handles):
594 raise NotImplementedError()
597 class SingleFieldGroup(FieldGroup, FieldDescriptor):
598 """A FieldGroup that contains a single FieldDescriptor."""
600 def __init__(self, name, field_type, index, version, default_value=None):
601 FieldDescriptor.__init__(
602 self, name, field_type, index, version, default_value)
603 FieldGroup.__init__(self, [self])
605 def GetTypeCode(self):
606 return self.field_type.GetTypeCode()
608 def GetByteSize(self):
609 return self.field_type.GetByteSize()
611 def GetVersion(self):
614 def Serialize(self, obj, data_offset, data, handle_offset):
615 value = getattr(obj, self.name)
616 return self.field_type.Serialize(value, data_offset, data, handle_offset)
618 def Deserialize(self, value, data, handles):
619 entity = self.field_type.Deserialize(value, data, handles)
620 return { self.name: entity }
623 class BooleanGroup(FieldGroup):
624 """A FieldGroup to pack booleans."""
625 def __init__(self, descriptors):
626 FieldGroup.__init__(self, descriptors)
627 self.version = min([descriptor.version for descriptor in descriptors])
629 def GetTypeCode(self):
632 def GetByteSize(self):
635 def GetVersion(self):
638 def Serialize(self, obj, data_offset, data, handle_offset):
639 value = _ConvertBooleansToByte(
640 [getattr(obj, field.name) for field in self.GetDescriptors()])
643 def Deserialize(self, value, data, handles):
644 values = itertools.izip_longest([x.name for x in self.descriptors],
645 _ConvertByteToBooleans(value),
650 def _SerializeNativeArray(value, data_offset, data, length):
651 data_size = len(data)
652 data.extend(bytearray(serialization.HEADER_STRUCT.size))
653 data.extend(buffer(value))
654 data_length = len(data) - data_size
655 data.extend(bytearray(serialization.NeededPaddingForAlignment(data_length)))
656 serialization.HEADER_STRUCT.pack_into(data, data_size, data_length, length)
657 return (data_offset, [])
660 def _ConvertBooleansToByte(booleans):
661 """Pack a list of booleans into an integer."""
662 return reduce(lambda x, y: x * 2 + y, reversed(booleans), 0)
665 def _ConvertByteToBooleans(value, min_size=0):
666 "Unpack an integer into a list of booleans."""
669 res.append(bool(value&1))
671 res.extend([False] * (min_size - len(res)))