Index: mojo/public/python/mojo/bindings/serialization.py |
diff --git a/mojo/public/python/mojo/bindings/serialization.py b/mojo/public/python/mojo/bindings/serialization.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5daad85f5aaf0687b1b3f41547a87ce71dfd3c67 |
--- /dev/null |
+++ b/mojo/public/python/mojo/bindings/serialization.py |
@@ -0,0 +1,98 @@ |
+# Copyright 2014 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+"""Utility classes for serialization""" |
+ |
+import struct |
+ |
+ |
+# Format of a header for a struct or an array. |
+HEADER_STRUCT = struct.Struct("=II") |
+ |
+ |
+class SerializationException(Exception): |
+ """Error when strying to serialize a struct.""" |
+ pass |
+ |
+ |
+class Serialization(object): |
+ """ |
+ Helper class to serialize/deserialize a struct. |
+ """ |
+ def __init__(self, groups): |
+ self._groups = groups |
+ self.version = _GetVersion(groups) |
+ main_struct = _GetStruct(groups) |
+ self.size = HEADER_STRUCT.size + main_struct.size |
+ self._struct_per_version = { |
+ self.version: main_struct, |
+ } |
+ |
+ def _GetMainStruct(self): |
+ return self._GetStruct(self.version) |
+ |
+ def _GetStruct(self, version): |
+ # If asking for a greater ver |
+ version = min(version, self.version) |
+ if version not in self._struct_per_version: |
+ self._struct_per_version[version] = _GetStruct(_FilterGroups(self._groups, |
+ version)) |
+ return self._struct_per_version[version] |
+ |
+ def Serialize(self, obj, handle_offset): |
+ """ |
+ Serialize the given obj. handle_offset is the the first value to use when |
+ encoding handles. |
+ """ |
+ handles = [] |
+ data = bytearray(self.size) |
+ HEADER_STRUCT.pack_into(data, 0, self.size, self.version) |
+ position = HEADER_STRUCT.size |
+ to_pack = [] |
+ for group in self._groups: |
+ position = position + NeededPaddingForAlignment(position, |
+ group.GetByteSize()) |
+ (entry, new_handles) = group.Serialize( |
+ obj, |
+ len(data) - position, |
+ data, |
+ handle_offset + len(handles)) |
+ to_pack.append(entry) |
+ handles.extend(new_handles) |
+ position = position + group.GetByteSize() |
+ self._GetMainStruct().pack_into(data, HEADER_STRUCT.size, *to_pack) |
+ return (data, handles) |
+ |
+ |
+def NeededPaddingForAlignment(value, alignment=8): |
+ """Returns the padding necessary to align value with the given alignment.""" |
sdefresne
2014/09/15 08:46:54
nit: this method could return a tuple padding_leng
qsr
2014/09/15 11:01:53
Not really. It is used that way only once, but I u
sdefresne
2014/09/15 11:14:46
Make sense, thank you for the justification.
qsr
2014/09/15 11:42:00
Acknowledged.
|
+ if value % alignment: |
+ return alignment - (value % alignment) |
+ return 0 |
+ |
+ |
+def _GetVersion(groups): |
+ return reduce(lambda x, y: x+y, [len(x.descriptors) for x in groups]) |
sdefresne
2014/09/15 08:46:54
nit: "reduce(lambda x, y: x+y, [...])" can be rewr
qsr
2014/09/15 11:01:53
Done.
|
+ |
+ |
+def _FilterGroups(groups, version): |
+ return [group for group in groups if group.version < version] |
+ |
+ |
+def _GetStruct(groups): |
+ index = 0 |
+ codes = [ '=' ] |
+ for group in groups: |
+ code = group.GetTypeCode() |
+ size = group.GetByteSize() |
+ needed_padding = NeededPaddingForAlignment(index, size) |
+ if needed_padding: |
+ codes.append('x' * needed_padding) |
+ index = index + needed_padding |
+ codes.append(code) |
+ index = index + size |
+ end_alignment = index % 8 |
sdefresne
2014/09/15 08:46:54
nit: you can use NeededPaddingForAlignment here.
qsr
2014/09/15 11:01:53
Done.
|
+ if end_alignment: |
+ codes.append('x' * (8 - end_alignment)) |
+ return struct.Struct(''.join(codes)) |