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""" 6The descriptors used to define generated elements of the mojo python bindings. 7""" 8 9import array 10import itertools 11import struct 12 13# pylint: disable=F0401 14import mojo.bindings.serialization as serialization 15import mojo.system 16 17 18class Type(object): 19 """Describes the type of a struct field or a method parameter,""" 20 21 def Convert(self, value): # pylint: disable=R0201 22 """ 23 Convert the given value into its canonical representation, raising an 24 exception if the value cannot be converted. 25 """ 26 return value 27 28 def GetDefaultValue(self, value): 29 """ 30 Returns the default value for this type associated with the given value. 31 This method must be able to correcly handle value being None. 32 """ 33 return self.Convert(value) 34 35 36class SerializableType(Type): 37 """Describe a type that can be serialized by itself.""" 38 39 def __init__(self, typecode): 40 Type.__init__(self) 41 self.typecode = typecode 42 self.byte_size = struct.calcsize('=%s' % self.GetTypeCode()) 43 44 def GetTypeCode(self): 45 """ 46 Returns the type code (as defined by the struct module) used to encode 47 this type. 48 """ 49 return self.typecode 50 51 def GetByteSize(self): 52 """ 53 Returns the size of the encoding of this type. 54 """ 55 return self.byte_size 56 57 def Serialize(self, value, data_offset, data, handle_offset): 58 """ 59 Serialize a value of this type. 60 61 Args: 62 value: the value to serialize. 63 data_offset: the offset to the end of the data bytearray. Used to encode 64 pointers. 65 data: the bytearray to append additional data to. 66 handle_offset: the offset to use to encode handles. 67 68 Returns a a tuple where the first element is the value to encode, and the 69 second is the array of handles to add to the message. 70 """ 71 raise NotImplementedError() 72 73 def Deserialize(self, value, data, handles): 74 """ 75 Deserialize a value of this type. 76 77 Args: 78 value: the base value for this type. This is always a numeric type, and 79 corresponds to the first element in the tuple returned by 80 Serialize. 81 data: the bytearray to retrieve additional data from. 82 handles: the array of handles contained in the message to deserialize. 83 84 Returns the deserialized value. 85 """ 86 raise NotImplementedError() 87 88 89class BooleanType(Type): 90 """Type object for booleans""" 91 92 def Convert(self, value): 93 return bool(value) 94 95 96class NumericType(SerializableType): 97 """Base Type object for all numeric types""" 98 99 def GetDefaultValue(self, value): 100 if value is None: 101 return self.Convert(0) 102 return self.Convert(value) 103 104 def Serialize(self, value, data_offset, data, handle_offset): 105 return (value, []) 106 107 def Deserialize(self, value, data, handles): 108 return value 109 110 111class IntegerType(NumericType): 112 """Type object for integer types.""" 113 114 def __init__(self, typecode): 115 NumericType.__init__(self, typecode) 116 size = 8 * self.byte_size 117 signed = typecode.islower() 118 if signed: 119 self._min_value = -(1 << (size - 1)) 120 self._max_value = (1 << (size - 1)) - 1 121 else: 122 self._min_value = 0 123 self._max_value = (1 << size) - 1 124 125 def Convert(self, value): 126 if value is None: 127 raise TypeError('None is not an integer.') 128 if not isinstance(value, (int, long)): 129 raise TypeError('%r is not an integer type' % value) 130 if value < self._min_value or value > self._max_value: 131 raise OverflowError('%r is not in the range [%d, %d]' % 132 (value, self._min_value, self._max_value)) 133 return value 134 135 136class FloatType(NumericType): 137 """Type object for floating point number types.""" 138 139 def Convert(self, value): 140 if value is None: 141 raise TypeError('None is not an floating point number.') 142 if not isinstance(value, (int, long, float)): 143 raise TypeError('%r is not a numeric type' % value) 144 return float(value) 145 146 147class PointerType(SerializableType): 148 """Base Type object for pointers.""" 149 150 def __init__(self, nullable=False): 151 SerializableType.__init__(self, 'Q') 152 self.nullable = nullable 153 154 def Serialize(self, value, data_offset, data, handle_offset): 155 if value is None and not self.nullable: 156 raise serialization.SerializationException( 157 'Trying to serialize null for non nullable type.') 158 if value is None: 159 return (0, []) 160 return self.SerializePointer(value, data_offset, data, handle_offset) 161 162 def Deserialize(self, value, data, handles): 163 if value == 0: 164 if not self.nullable: 165 raise serialization.DeserializationException( 166 'Trying to deserialize null for non nullable type.') 167 return None 168 pointed_data = buffer(data, value) 169 (size, nb_elements) = serialization.HEADER_STRUCT.unpack_from(pointed_data) 170 return self.DeserializePointer(size, nb_elements, pointed_data, handles) 171 172 def SerializePointer(self, value, data_offset, data, handle_offset): 173 """Serialize the not null value.""" 174 raise NotImplementedError() 175 176 def DeserializePointer(self, size, nb_elements, data, handles): 177 raise NotImplementedError() 178 179 180class StringType(PointerType): 181 """ 182 Type object for strings. 183 184 Strings are represented as unicode, and the conversion is done using the 185 default encoding if a string instance is used. 186 """ 187 188 def __init__(self, nullable=False): 189 PointerType.__init__(self, nullable) 190 self._array_type = NativeArrayType('B', nullable) 191 192 def Convert(self, value): 193 if value is None or isinstance(value, unicode): 194 return value 195 if isinstance(value, str): 196 return unicode(value) 197 raise TypeError('%r is not a string' % value) 198 199 def SerializePointer(self, value, data_offset, data, handle_offset): 200 string_array = array.array('b') 201 string_array.fromstring(value.encode('utf8')) 202 return self._array_type.SerializeArray( 203 string_array, data_offset, data, handle_offset) 204 205 def DeserializePointer(self, size, nb_elements, data, handles): 206 string_array = self._array_type.DeserializeArray( 207 size, nb_elements, data, handles) 208 return unicode(string_array.tostring(), 'utf8') 209 210 211class HandleType(SerializableType): 212 """Type object for handles.""" 213 214 def __init__(self, nullable=False): 215 SerializableType.__init__(self, 'i') 216 self.nullable = nullable 217 218 def Convert(self, value): 219 if value is None: 220 return mojo.system.Handle() 221 if not isinstance(value, mojo.system.Handle): 222 raise TypeError('%r is not a handle' % value) 223 return value 224 225 def Serialize(self, value, data_offset, data, handle_offset): 226 if not value.IsValid() and not self.nullable: 227 raise serialization.SerializationException( 228 'Trying to serialize null for non nullable type.') 229 if not value.IsValid(): 230 return (-1, []) 231 return (handle_offset, [value]) 232 233 def Deserialize(self, value, data, handles): 234 if value == -1: 235 if not self.nullable: 236 raise serialization.DeserializationException( 237 'Trying to deserialize null for non nullable type.') 238 return mojo.system.Handle() 239 # TODO(qsr) validate handle order 240 return handles[value] 241 242 243class BaseArrayType(PointerType): 244 """Abstract Type object for arrays.""" 245 246 def __init__(self, nullable=False, length=0): 247 PointerType.__init__(self, nullable) 248 self.length = length 249 250 def SerializePointer(self, value, data_offset, data, handle_offset): 251 if self.length != 0 and len(value) != self.length: 252 raise serialization.SerializationException('Incorrect array size') 253 return self.SerializeArray(value, data_offset, data, handle_offset) 254 255 def SerializeArray(self, value, data_offset, data, handle_offset): 256 """Serialize the not null array.""" 257 raise NotImplementedError() 258 259 def DeserializePointer(self, size, nb_elements, data, handles): 260 if self.length != 0 and size != self.length: 261 raise serialization.DeserializationException('Incorrect array size') 262 return self.DeserializeArray(size, nb_elements, data, handles) 263 264 def DeserializeArray(self, size, nb_elements, data, handles): 265 raise NotImplementedError() 266 267 268class BooleanArrayType(BaseArrayType): 269 270 def __init__(self, nullable=False, length=0): 271 BaseArrayType.__init__(self, nullable, length) 272 self._array_type = NativeArrayType('B', nullable) 273 274 def Convert(self, value): 275 if value is None: 276 return value 277 return [TYPE_BOOL.Convert(x) for x in value] 278 279 def SerializeArray(self, value, data_offset, data, handle_offset): 280 groups = [value[i:i+8] for i in range(0, len(value), 8)] 281 converted = array.array('B', [_ConvertBooleansToByte(x) for x in groups]) 282 return _SerializeNativeArray(converted, data_offset, data, len(value)) 283 284 def DeserializeArray(self, size, nb_elements, data, handles): 285 converted = self._array_type.DeserializeArray( 286 size, nb_elements, data, handles) 287 elements = list(itertools.islice( 288 itertools.chain.from_iterable( 289 [_ConvertByteToBooleans(x, 8) for x in converted]), 290 0, 291 nb_elements)) 292 return elements 293 294 295class GenericArrayType(BaseArrayType): 296 """Type object for arrays of pointers.""" 297 298 def __init__(self, sub_type, nullable=False, length=0): 299 BaseArrayType.__init__(self, nullable, length) 300 assert isinstance(sub_type, SerializableType) 301 self.sub_type = sub_type 302 303 def Convert(self, value): 304 if value is None: 305 return value 306 return [self.sub_type.Convert(x) for x in value] 307 308 def SerializeArray(self, value, data_offset, data, handle_offset): 309 size = (serialization.HEADER_STRUCT.size + 310 self.sub_type.GetByteSize() * len(value)) 311 data_end = len(data) 312 position = len(data) + serialization.HEADER_STRUCT.size 313 data.extend(bytearray(size + 314 serialization.NeededPaddingForAlignment(size))) 315 returned_handles = [] 316 to_pack = [] 317 for item in value: 318 (new_data, new_handles) = self.sub_type.Serialize( 319 item, 320 len(data) - position, 321 data, 322 handle_offset + len(returned_handles)) 323 to_pack.append(new_data) 324 returned_handles.extend(new_handles) 325 position = position + self.sub_type.GetByteSize() 326 serialization.HEADER_STRUCT.pack_into(data, data_end, size, len(value)) 327 struct.pack_into('%d%s' % (len(value), self.sub_type.GetTypeCode()), 328 data, 329 data_end + serialization.HEADER_STRUCT.size, 330 *to_pack) 331 return (data_offset, returned_handles) 332 333 def DeserializeArray(self, size, nb_elements, data, handles): 334 values = struct.unpack_from( 335 '%d%s' % (nb_elements, self.sub_type.GetTypeCode()), 336 buffer(data, serialization.HEADER_STRUCT.size)) 337 result = [] 338 position = serialization.HEADER_STRUCT.size 339 for value in values: 340 result.append( 341 self.sub_type.Deserialize(value, buffer(data, position), handles)) 342 position += self.sub_type.GetByteSize() 343 return result 344 345 346class NativeArrayType(BaseArrayType): 347 """Type object for arrays of native types.""" 348 349 def __init__(self, typecode, nullable=False, length=0): 350 BaseArrayType.__init__(self, nullable, length) 351 self.array_typecode = typecode 352 353 def Convert(self, value): 354 if value is None: 355 return value 356 if (isinstance(value, array.array) and 357 value.array_typecode == self.array_typecode): 358 return value 359 return array.array(self.array_typecode, value) 360 361 def SerializeArray(self, value, data_offset, data, handle_offset): 362 return _SerializeNativeArray(value, data_offset, data, len(value)) 363 364 def DeserializeArray(self, size, nb_elements, data, handles): 365 result = array.array(self.array_typecode) 366 result.fromstring(buffer(data, 367 serialization.HEADER_STRUCT.size, 368 size - serialization.HEADER_STRUCT.size)) 369 return result 370 371 372class StructType(PointerType): 373 """Type object for structs.""" 374 375 def __init__(self, struct_type, nullable=False): 376 PointerType.__init__(self) 377 self.struct_type = struct_type 378 self.nullable = nullable 379 380 def Convert(self, value): 381 if value is None or isinstance(value, self.struct_type): 382 return value 383 raise TypeError('%r is not an instance of %r' % (value, self.struct_type)) 384 385 def GetDefaultValue(self, value): 386 if value: 387 return self.struct_type() 388 return None 389 390 def SerializePointer(self, value, data_offset, data, handle_offset): 391 (new_data, new_handles) = value.Serialize(handle_offset) 392 data.extend(new_data) 393 return (data_offset, new_handles) 394 395 def DeserializePointer(self, size, nb_elements, data, handles): 396 return self.struct_type.Deserialize(data, handles) 397 398 399class NoneType(SerializableType): 400 """Placeholder type, used temporarily until all mojo types are handled.""" 401 402 def __init__(self): 403 SerializableType.__init__(self, 'B') 404 405 def Convert(self, value): 406 return None 407 408 def Serialize(self, value, data_offset, data, handle_offset): 409 return (0, []) 410 411 def Deserialize(self, value, data, handles): 412 return None 413 414 415TYPE_NONE = NoneType() 416 417TYPE_BOOL = BooleanType() 418 419TYPE_INT8 = IntegerType('b') 420TYPE_INT16 = IntegerType('h') 421TYPE_INT32 = IntegerType('i') 422TYPE_INT64 = IntegerType('q') 423 424TYPE_UINT8 = IntegerType('B') 425TYPE_UINT16 = IntegerType('H') 426TYPE_UINT32 = IntegerType('I') 427TYPE_UINT64 = IntegerType('Q') 428 429TYPE_FLOAT = FloatType('f') 430TYPE_DOUBLE = FloatType('d') 431 432TYPE_STRING = StringType() 433TYPE_NULLABLE_STRING = StringType(True) 434 435TYPE_HANDLE = HandleType() 436TYPE_NULLABLE_HANDLE = HandleType(True) 437 438 439class FieldDescriptor(object): 440 """Describes a field in a generated struct.""" 441 442 def __init__(self, name, field_type, field_number, default_value=None): 443 self.name = name 444 self.field_type = field_type 445 self.field_number = field_number 446 self._default_value = default_value 447 448 def GetDefaultValue(self): 449 return self.field_type.GetDefaultValue(self._default_value) 450 451 452class FieldGroup(object): 453 """ 454 Describe a list of field in the generated struct that must be 455 serialized/deserialized together. 456 """ 457 def __init__(self, descriptors): 458 self.descriptors = descriptors 459 460 def GetDescriptors(self): 461 return self.descriptors 462 463 def GetTypeCode(self): 464 raise NotImplementedError() 465 466 def GetByteSize(self): 467 raise NotImplementedError() 468 469 def GetVersion(self): 470 raise NotImplementedError() 471 472 def Serialize(self, obj, data_offset, data, handle_offset): 473 raise NotImplementedError() 474 475 def Deserialize(self, value, data, handles): 476 raise NotImplementedError() 477 478 479class SingleFieldGroup(FieldGroup, FieldDescriptor): 480 """A FieldGroup that contains a single FieldDescriptor.""" 481 482 def __init__(self, name, field_type, field_number, default_value=None): 483 FieldDescriptor.__init__( 484 self, name, field_type, field_number, default_value) 485 FieldGroup.__init__(self, [self]) 486 487 def GetTypeCode(self): 488 return self.field_type.GetTypeCode() 489 490 def GetByteSize(self): 491 return self.field_type.GetByteSize() 492 493 def GetVersion(self): 494 return self.field_number 495 496 def Serialize(self, obj, data_offset, data, handle_offset): 497 value = getattr(obj, self.name) 498 return self.field_type.Serialize(value, data_offset, data, handle_offset) 499 500 def Deserialize(self, value, data, handles): 501 entity = self.field_type.Deserialize(value, data, handles) 502 return { self.name: entity } 503 504 505class BooleanGroup(FieldGroup): 506 """A FieldGroup to pack booleans.""" 507 def __init__(self, descriptors): 508 FieldGroup.__init__(self, descriptors) 509 self.version = min([descriptor.field_number for descriptor in descriptors]) 510 511 def GetTypeCode(self): 512 return 'B' 513 514 def GetByteSize(self): 515 return 1 516 517 def GetVersion(self): 518 return self.version 519 520 def Serialize(self, obj, data_offset, data, handle_offset): 521 value = _ConvertBooleansToByte( 522 [getattr(obj, field.name) for field in self.GetDescriptors()]) 523 return (value, []) 524 525 def Deserialize(self, value, data, handles): 526 values = itertools.izip_longest([x.name for x in self.descriptors], 527 _ConvertByteToBooleans(value), 528 fillvalue=False) 529 return dict(values) 530 531 532def _SerializeNativeArray(value, data_offset, data, length): 533 data_size = len(data) 534 data.extend(bytearray(serialization.HEADER_STRUCT.size)) 535 data.extend(buffer(value)) 536 data_length = len(data) - data_size 537 data.extend(bytearray(serialization.NeededPaddingForAlignment(data_length))) 538 serialization.HEADER_STRUCT.pack_into(data, data_size, data_length, length) 539 return (data_offset, []) 540 541 542def _ConvertBooleansToByte(booleans): 543 """Pack a list of booleans into an integer.""" 544 return reduce(lambda x, y: x * 2 + y, reversed(booleans), 0) 545 546 547def _ConvertByteToBooleans(value, min_size=0): 548 "Unpack an integer into a list of booleans.""" 549 res = [] 550 while value: 551 res.append(bool(value&1)) 552 value = value / 2 553 res.extend([False] * (min_size - len(res))) 554 return res 555