Index: mojo/public/python/mojo/bindings/descriptor.py |
diff --git a/mojo/public/python/mojo/bindings/descriptor.py b/mojo/public/python/mojo/bindings/descriptor.py |
index 06d636b7db6631d4d2d0fe41ab2aa68d17846469..42fb3a4da98888e34818b950cea0bf79abe828e2 100644 |
--- a/mojo/public/python/mojo/bindings/descriptor.py |
+++ b/mojo/public/python/mojo/bindings/descriptor.py |
@@ -7,6 +7,7 @@ The descriptors used to define generated elements of the mojo python bindings. |
""" |
import array |
+import itertools |
import struct |
# pylint: disable=F0401 |
@@ -55,7 +56,7 @@ class SerializableType(Type): |
def Serialize(self, value, data_offset, data, handle_offset): |
""" |
- Serialize an value of this type. |
+ Serialize a value of this type. |
Args: |
value: the value to serialize. |
@@ -69,6 +70,21 @@ class SerializableType(Type): |
""" |
raise NotImplementedError() |
+ def Deserialize(self, value, data, handles): |
+ """ |
+ Deserialize a value of this type. |
+ |
+ Args: |
+ value: the base value for this type. This is always a numeric type, and |
+ corresponds to the first element in the tuple returned by |
+ Serialize. |
+ data: the bytearray to retrieve additional data from. |
+ handles: the array of handles contained in the message to deserialize. |
+ |
+ Returns the deserialized value. |
+ """ |
+ raise NotImplementedError() |
+ |
class BooleanType(Type): |
"""Type object for booleans""" |
@@ -88,6 +104,9 @@ class NumericType(SerializableType): |
def Serialize(self, value, data_offset, data, handle_offset): |
return (value, []) |
+ def Deserialize(self, value, data, handles): |
+ return value |
+ |
class IntegerType(NumericType): |
"""Type object for integer types.""" |
@@ -135,15 +154,28 @@ class PointerType(SerializableType): |
def Serialize(self, value, data_offset, data, handle_offset): |
if value is None and not self.nullable: |
raise serialization.SerializationException( |
- "Trying to serialize null for non nullable type.") |
+ 'Trying to serialize null for non nullable type.') |
if value is None: |
return (0, []) |
return self.SerializePointer(value, data_offset, data, handle_offset) |
+ def Deserialize(self, value, data, handles): |
+ if value == 0: |
+ if not self.nullable: |
+ raise serialization.DeserializationException( |
+ 'Trying to deserialize null for non nullable type.') |
+ return None |
+ pointed_data = data[value:] |
+ (size, nb_elements) = serialization.HEADER_STRUCT.unpack_from(pointed_data) |
+ return self.DeserializePointer(size, nb_elements, pointed_data, handles) |
+ |
def SerializePointer(self, value, data_offset, data, handle_offset): |
"""Serialize the not null value.""" |
raise NotImplementedError() |
+ def DeserializePointer(self, size, nb_elements, data, handles): |
+ raise NotImplementedError() |
+ |
class StringType(PointerType): |
""" |
@@ -170,6 +202,11 @@ class StringType(PointerType): |
return self._array_type.SerializeArray( |
string_array, data_offset, data, handle_offset) |
+ def DeserializePointer(self, size, nb_elements, data, handles): |
+ string_array = self._array_type.DeserializeArray( |
+ size, nb_elements, data, handles) |
+ return unicode(string_array.tostring(), 'utf8') |
+ |
class HandleType(SerializableType): |
"""Type object for handles.""" |
@@ -188,11 +225,20 @@ class HandleType(SerializableType): |
def Serialize(self, value, data_offset, data, handle_offset): |
if not value.IsValid() and not self.nullable: |
raise serialization.SerializationException( |
- "Trying to serialize null for non nullable type.") |
+ 'Trying to serialize null for non nullable type.') |
if not value.IsValid(): |
return (-1, []) |
return (handle_offset, [value]) |
+ def Deserialize(self, value, data, handles): |
+ if value == -1: |
+ if not self.nullable: |
+ raise serialization.DeserializationException( |
+ 'Trying to deserialize null for non nullable type.') |
+ return mojo.system.Handle() |
+ # TODO(qsr) validate handle order |
+ return handles[value] |
+ |
class BaseArrayType(PointerType): |
"""Abstract Type object for arrays.""" |
@@ -203,13 +249,22 @@ class BaseArrayType(PointerType): |
def SerializePointer(self, value, data_offset, data, handle_offset): |
if self.length != 0 and len(value) != self.length: |
- raise serialization.SerializationException("Incorrect array size") |
+ raise serialization.SerializationException('Incorrect array size') |
return self.SerializeArray(value, data_offset, data, handle_offset) |
def SerializeArray(self, value, data_offset, data, handle_offset): |
"""Serialize the not null array.""" |
raise NotImplementedError() |
+ def DeserializePointer(self, size, nb_elements, data, handles): |
+ if self.length != 0 and size != self.length: |
+ raise serialization.DeserializationException('Incorrect array size') |
+ return self.DeserializeArray(size, nb_elements, data, handles) |
+ |
+ def DeserializeArray(self, size, nb_elements, data, handles): |
+ raise NotImplementedError() |
+ |
+ |
class BooleanArrayType(BaseArrayType): |
def __init__(self, nullable=False, length=0): |
@@ -224,8 +279,17 @@ class BooleanArrayType(BaseArrayType): |
def SerializeArray(self, value, data_offset, data, handle_offset): |
groups = [value[i:i+8] for i in range(0, len(value), 8)] |
converted = array.array('B', [_ConvertBooleansToByte(x) for x in groups]) |
- return self._array_type.SerializeArray( |
- converted, data_offset, data, handle_offset) |
+ return _SerializeNativeArray(converted, data_offset, data, len(value)) |
+ |
+ def DeserializeArray(self, size, nb_elements, data, handles): |
+ converted = self._array_type.DeserializeArray( |
+ size, nb_elements, data, handles) |
+ elements = list(itertools.islice( |
+ itertools.chain.from_iterable( |
+ [_ConvertByteToBooleans(x, 8) for x in converted]), |
+ 0, |
+ nb_elements)) |
+ return elements |
class GenericArrayType(BaseArrayType): |
@@ -245,12 +309,11 @@ class GenericArrayType(BaseArrayType): |
size = (serialization.HEADER_STRUCT.size + |
self.sub_type.GetByteSize() * len(value)) |
data_end = len(data) |
- position = len(data) - data_offset |
+ position = len(data) + serialization.HEADER_STRUCT.size |
data.extend(bytearray(size + |
serialization.NeededPaddingForAlignment(size))) |
returned_handles = [] |
to_pack = [] |
- position = position + 2 |
for item in value: |
(new_data, new_handles) = self.sub_type.Serialize( |
item, |
@@ -261,12 +324,23 @@ class GenericArrayType(BaseArrayType): |
returned_handles.extend(new_handles) |
position = position + self.sub_type.GetByteSize() |
serialization.HEADER_STRUCT.pack_into(data, data_end, size, len(value)) |
- struct.pack_into("%d%s" % (len(value), self.sub_type.GetTypeCode()), |
+ struct.pack_into('%d%s' % (len(value), self.sub_type.GetTypeCode()), |
data, |
data_end + serialization.HEADER_STRUCT.size, |
*to_pack) |
return (data_offset, returned_handles) |
+ def DeserializeArray(self, size, nb_elements, data, handles): |
+ values = struct.unpack_from( |
+ '%d%s' % (nb_elements, self.sub_type.GetTypeCode()), |
+ data[serialization.HEADER_STRUCT.size:]) |
+ result = [] |
+ position = serialization.HEADER_STRUCT.size |
+ for value in values: |
+ result.append(self.sub_type.Deserialize(value, data[position:], handles)) |
+ position += self.sub_type.GetByteSize() |
+ return result |
+ |
class NativeArrayType(BaseArrayType): |
"""Type object for arrays of native types.""" |
@@ -284,15 +358,12 @@ class NativeArrayType(BaseArrayType): |
return array.array(self.array_typecode, value) |
def SerializeArray(self, value, data_offset, data, handle_offset): |
- data_size = len(data) |
- data.extend(bytearray(serialization.HEADER_STRUCT.size)) |
- data.extend(value.tostring()) |
- data_length = len(data) - data_size |
- data.extend(bytearray( |
- serialization.NeededPaddingForAlignment(data_length))) |
- serialization.HEADER_STRUCT.pack_into( |
- data, data_size, data_length, len(value)) |
- return (data_offset, []) |
+ return _SerializeNativeArray(value, data_offset, data, len(value)) |
+ |
+ def DeserializeArray(self, size, nb_elements, data, handles): |
+ result = array.array(self.array_typecode) |
+ result.fromstring(data[serialization.HEADER_STRUCT.size:size].tobytes()) |
+ return result |
class StructType(PointerType): |
@@ -318,6 +389,9 @@ class StructType(PointerType): |
data.extend(new_data) |
return (data_offset, new_handles) |
+ def DeserializePointer(self, size, nb_elements, data, handles): |
+ return self.struct_type.Deserialize(data, handles) |
+ |
class NoneType(SerializableType): |
"""Placeholder type, used temporarily until all mojo types are handled.""" |
@@ -331,6 +405,9 @@ class NoneType(SerializableType): |
def Serialize(self, value, data_offset, data, handle_offset): |
return (0, []) |
+ def Deserialize(self, value, data, handles): |
+ return None |
sdefresne
2014/09/18 12:56:21
Don't you want to validate that the value is 0?
qsr
2014/09/18 14:16:36
Not really. NoneType is not there to stay. But I h
sdefresne
2014/09/18 15:01:49
Acknowledged.
|
+ |
TYPE_NONE = NoneType() |
@@ -392,6 +469,9 @@ class FieldGroup(object): |
def Serialize(self, obj, data_offset, data, handle_offset): |
raise NotImplementedError() |
+ def Deserialize(self, value, data, handles): |
+ raise NotImplementedError() |
+ |
class SingleFieldGroup(FieldGroup, FieldDescriptor): |
"""A FieldGroup that contains a single FieldDescriptor.""" |
@@ -414,6 +494,10 @@ class SingleFieldGroup(FieldGroup, FieldDescriptor): |
value = getattr(obj, self.name) |
return self.field_type.Serialize(value, data_offset, data, handle_offset) |
+ def Deserialize(self, value, data, handles): |
+ entity = self.field_type.Deserialize(value, data, handles) |
+ return { self.name: entity } |
+ |
class BooleanGroup(FieldGroup): |
"""A FieldGroup to pack booleans.""" |
@@ -422,7 +506,7 @@ class BooleanGroup(FieldGroup): |
self.version = min([descriptor.field_number for descriptor in descriptors]) |
def GetTypeCode(self): |
- return "B" |
+ return 'B' |
def GetByteSize(self): |
return 1 |
@@ -435,7 +519,33 @@ class BooleanGroup(FieldGroup): |
[getattr(obj, field.name) for field in self.GetDescriptors()]) |
return (value, []) |
+ def Deserialize(self, value, data, handles): |
+ values = itertools.izip_longest([x.name for x in self.descriptors], |
+ _ConvertByteToBooleans(value), |
+ fillvalue=False) |
+ return dict(values) |
+ |
+ |
+def _SerializeNativeArray(value, data_offset, data, length): |
+ data_size = len(data) |
+ data.extend(bytearray(serialization.HEADER_STRUCT.size)) |
+ data.extend(value.tostring()) |
+ data_length = len(data) - data_size |
+ data.extend(bytearray(serialization.NeededPaddingForAlignment(data_length))) |
+ serialization.HEADER_STRUCT.pack_into(data, data_size, data_length, length) |
+ return (data_offset, []) |
+ |
def _ConvertBooleansToByte(booleans): |
"""Pack a list of booleans into an integer.""" |
return reduce(lambda x, y: x * 2 + y, reversed(booleans), 0) |
+ |
+ |
+def _ConvertByteToBooleans(value, min_size=0): |
+ "Unpack an integer into a list of booleans.""" |
+ res = [] |
+ while value: |
+ res.append(bool(value&1)) |
+ value = value / 2 |
+ res.extend([False] * (min_size - len(res))) |
+ return res |