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..cb68d4a2d2429817614af124c59e4ecb7d3bf573 |
--- /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.""" |
+ if value % alignment: |
+ return alignment - (value % alignment) |
+ return 0 |
+ |
+ |
+def _GetVersion(groups): |
+ return sum([len(x.descriptors) for x in groups]) |
+ |
+ |
+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 |
+ alignment_needed = NeededPaddingForAlignment(index) |
+ if alignment_needed: |
+ codes.append('x' * alignment_needed) |
+ return struct.Struct(''.join(codes)) |