Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / mojo / public / python / mojo / bindings / descriptor.py
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, data, handles):
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, data, handles):
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, data, handles):
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     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)
173
174   def SerializePointer(self, value, data_offset, data, handle_offset):
175     """Serialize the not null value."""
176     raise NotImplementedError()
177
178   def DeserializePointer(self, size, nb_elements, data, handles):
179     raise NotImplementedError()
180
181
182 class StringType(PointerType):
183   """
184   Type object for strings.
185
186   Strings are represented as unicode, and the conversion is done using the
187   default encoding if a string instance is used.
188   """
189
190   def __init__(self, nullable=False):
191     PointerType.__init__(self, nullable)
192     self._array_type = NativeArrayType('B', nullable)
193
194   def Convert(self, value):
195     if value is None or isinstance(value, unicode):
196       return value
197     if isinstance(value, str):
198       return unicode(value)
199     raise TypeError('%r is not a string' % value)
200
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)
206
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')
211
212
213 class BaseHandleType(SerializableType):
214   """Type object for handles."""
215
216   def __init__(self, nullable=False):
217     SerializableType.__init__(self, 'i')
218     self.nullable = nullable
219
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():
226       return (-1, [])
227     return (handle_offset, [handle])
228
229   def Deserialize(self, value, data, handles):
230     if value == -1:
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])
237
238   def FromHandle(self, handle):
239     raise NotImplementedError()
240
241   def ToHandle(self, value):
242     raise NotImplementedError()
243
244
245 class HandleType(BaseHandleType):
246   """Type object for handles."""
247
248   def Convert(self, value):
249     if value is None:
250       return mojo.system.Handle()
251     if not isinstance(value, mojo.system.Handle):
252       raise TypeError('%r is not a handle' % value)
253     return value
254
255   def FromHandle(self, handle):
256     return handle
257
258   def ToHandle(self, value):
259     return value
260
261
262 class InterfaceRequestType(BaseHandleType):
263   """Type object for interface requests."""
264
265   def Convert(self, value):
266     if value is None:
267       return reflection.InterfaceRequest(mojo.system.Handle())
268     if not isinstance(value, reflection.InterfaceRequest):
269       raise TypeError('%r is not an interface request' % value)
270     return value
271
272   def FromHandle(self, handle):
273     return reflection.InterfaceRequest(handle)
274
275   def ToHandle(self, value):
276     return value.PassMessagePipe()
277
278
279 class InterfaceType(BaseHandleType):
280   """Type object for interfaces."""
281
282   def __init__(self, interface_getter, nullable=False):
283     BaseHandleType.__init__(self, nullable)
284     self._interface_getter = interface_getter
285     self._interface = None
286
287   def Convert(self, value):
288     if value is None or isinstance(value, self.interface):
289       return value
290     raise TypeError('%r is not an instance of ' % self.interface)
291
292   @property
293   def interface(self):
294     if not self._interface:
295       self._interface = self._interface_getter()
296     return self._interface
297
298   def FromHandle(self, handle):
299     if handle.IsValid():
300       return self.interface.manager.Proxy(handle)
301     return None
302
303   def ToHandle(self, value):
304     if not 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)
310     return pipe.handle1
311
312
313 class BaseArrayType(PointerType):
314   """Abstract Type object for arrays."""
315
316   def __init__(self, nullable=False, length=0):
317     PointerType.__init__(self, nullable)
318     self.length = length
319
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)
324
325   def SerializeArray(self, value, data_offset, data, handle_offset):
326     """Serialize the not null array."""
327     raise NotImplementedError()
328
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)
333
334   def DeserializeArray(self, size, nb_elements, data, handles):
335     raise NotImplementedError()
336
337
338 class BooleanArrayType(BaseArrayType):
339
340   def __init__(self, nullable=False, length=0):
341     BaseArrayType.__init__(self, nullable, length)
342     self._array_type = NativeArrayType('B', nullable)
343
344   def Convert(self, value):
345     if value is None:
346       return value
347     return [TYPE_BOOL.Convert(x) for x in value]
348
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))
353
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]),
360         0,
361         nb_elements))
362     return elements
363
364
365 class GenericArrayType(BaseArrayType):
366   """Type object for arrays of pointers."""
367
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
372
373   def Convert(self, value):
374     if value is None:
375       return value
376     return [self.sub_type.Convert(x) for x in value]
377
378   def SerializeArray(self, value, data_offset, data, handle_offset):
379     size = (serialization.HEADER_STRUCT.size +
380             self.sub_type.GetByteSize() * len(value))
381     data_end = len(data)
382     position = len(data) + serialization.HEADER_STRUCT.size
383     data.extend(bytearray(size +
384                           serialization.NeededPaddingForAlignment(size)))
385     returned_handles = []
386     to_pack = []
387     for item in value:
388       (new_data, new_handles) = self.sub_type.Serialize(
389           item,
390           len(data) - position,
391           data,
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()),
398                      data,
399                      data_end + serialization.HEADER_STRUCT.size,
400                      *to_pack)
401     return (data_offset, returned_handles)
402
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))
407     result = []
408     position = serialization.HEADER_STRUCT.size
409     for value in values:
410       result.append(
411           self.sub_type.Deserialize(value, buffer(data, position), handles))
412       position += self.sub_type.GetByteSize()
413     return result
414
415
416 class NativeArrayType(BaseArrayType):
417   """Type object for arrays of native types."""
418
419   def __init__(self, typecode, nullable=False, length=0):
420     BaseArrayType.__init__(self, nullable, length)
421     self.array_typecode = typecode
422
423   def Convert(self, value):
424     if value is None:
425       return value
426     if (isinstance(value, array.array) and
427         value.array_typecode == self.array_typecode):
428       return value
429     return array.array(self.array_typecode, value)
430
431   def SerializeArray(self, value, data_offset, data, handle_offset):
432     return _SerializeNativeArray(value, data_offset, data, len(value))
433
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))
439     return result
440
441
442 class StructType(PointerType):
443   """Type object for structs."""
444
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
450
451   @property
452   def struct_type(self):
453     if not self._struct_type:
454       self._struct_type = self._struct_type_getter()
455     return self._struct_type
456
457   def Convert(self, value):
458     if value is None or isinstance(value, self.struct_type):
459       return value
460     raise TypeError('%r is not an instance of %r' % (value, self.struct_type))
461
462   def GetDefaultValue(self, value):
463     if value:
464       return self.struct_type()
465     return None
466
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)
471
472   def DeserializePointer(self, size, nb_elements, data, handles):
473     return self.struct_type.Deserialize(data, handles)
474
475
476 class MapType(SerializableType):
477   """Type objects for maps."""
478
479   def __init__(self, key_type, value_type, nullable=False):
480     self._key_type = key_type
481     self._value_type = value_type
482     dictionary = {
483       '__metaclass__': reflection.MojoStructType,
484       '__module__': __name__,
485       'DESCRIPTOR': {
486         'fields': [
487           SingleFieldGroup('keys', MapType._GetArrayType(key_type), 0, 0),
488           SingleFieldGroup('values', MapType._GetArrayType(value_type), 1, 1),
489         ],
490       }
491     }
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)
495
496   def Convert(self, value):
497     if value is None:
498       return 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.')
503
504   def Serialize(self, value, data_offset, data, handle_offset):
505     s = None
506     if value:
507       keys, values = [], []
508       for key, value in value.iteritems():
509         keys.append(key)
510         values.append(value)
511       s = self.struct(keys=keys, values=values)
512     return self.struct_type.Serialize(s, data_offset, data, handle_offset)
513
514   def Deserialize(self, value, data, handles):
515     s = self.struct_type.Deserialize(value, data, handles)
516     if s:
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))
521     return None
522
523   @staticmethod
524   def _GetArrayType(t):
525     if t == TYPE_BOOL:
526       return BooleanArrayType()
527     else:
528       return GenericArrayType(t)
529
530
531 TYPE_BOOL = BooleanType()
532
533 TYPE_INT8 = IntegerType('b')
534 TYPE_INT16 = IntegerType('h')
535 TYPE_INT32 = IntegerType('i')
536 TYPE_INT64 = IntegerType('q')
537
538 TYPE_UINT8 = IntegerType('B')
539 TYPE_UINT16 = IntegerType('H')
540 TYPE_UINT32 = IntegerType('I')
541 TYPE_UINT64 = IntegerType('Q')
542
543 TYPE_FLOAT = FloatType('f')
544 TYPE_DOUBLE = FloatType('d')
545
546 TYPE_STRING = StringType()
547 TYPE_NULLABLE_STRING = StringType(True)
548
549 TYPE_HANDLE = HandleType()
550 TYPE_NULLABLE_HANDLE = HandleType(True)
551
552 TYPE_INTERFACE_REQUEST = InterfaceRequestType()
553 TYPE_NULLABLE_INTERFACE_REQUEST = InterfaceRequestType(True)
554
555
556 class FieldDescriptor(object):
557   """Describes a field in a generated struct."""
558
559   def __init__(self, name, field_type, index, version, default_value=None):
560     self.name = name
561     self.field_type = field_type
562     self.version = version
563     self.index = index
564     self._default_value = default_value
565
566   def GetDefaultValue(self):
567     return self.field_type.GetDefaultValue(self._default_value)
568
569
570 class FieldGroup(object):
571   """
572   Describe a list of field in the generated struct that must be
573   serialized/deserialized together.
574   """
575   def __init__(self, descriptors):
576     self.descriptors = descriptors
577
578   def GetDescriptors(self):
579     return self.descriptors
580
581   def GetTypeCode(self):
582     raise NotImplementedError()
583
584   def GetByteSize(self):
585     raise NotImplementedError()
586
587   def GetVersion(self):
588     raise NotImplementedError()
589
590   def Serialize(self, obj, data_offset, data, handle_offset):
591     raise NotImplementedError()
592
593   def Deserialize(self, value, data, handles):
594     raise NotImplementedError()
595
596
597 class SingleFieldGroup(FieldGroup, FieldDescriptor):
598   """A FieldGroup that contains a single FieldDescriptor."""
599
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])
604
605   def GetTypeCode(self):
606     return self.field_type.GetTypeCode()
607
608   def GetByteSize(self):
609     return self.field_type.GetByteSize()
610
611   def GetVersion(self):
612     return self.version
613
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)
617
618   def Deserialize(self, value, data, handles):
619     entity = self.field_type.Deserialize(value, data, handles)
620     return { self.name: entity }
621
622
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])
628
629   def GetTypeCode(self):
630     return 'B'
631
632   def GetByteSize(self):
633     return 1
634
635   def GetVersion(self):
636     return self.version
637
638   def Serialize(self, obj, data_offset, data, handle_offset):
639     value = _ConvertBooleansToByte(
640         [getattr(obj, field.name) for field in self.GetDescriptors()])
641     return (value, [])
642
643   def Deserialize(self, value, data, handles):
644     values =  itertools.izip_longest([x.name for x in self.descriptors],
645                                       _ConvertByteToBooleans(value),
646                                      fillvalue=False)
647     return dict(values)
648
649
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, [])
658
659
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)
663
664
665 def _ConvertByteToBooleans(value, min_size=0):
666   "Unpack an integer into a list of booleans."""
667   res = []
668   while value:
669     res.append(bool(value&1))
670     value = value / 2
671   res.extend([False] * (min_size - len(res)))
672   return res