Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 """Utility classes for serialization""" | |
| 6 | |
| 7 import struct | |
| 8 | |
| 9 | |
| 10 # Format of a header for a struct or an array. | |
| 11 HEADER_STRUCT = struct.Struct("=II") | |
| 12 | |
| 13 | |
| 14 class SerializationException(Exception): | |
| 15 """Error when strying to serialize a struct.""" | |
| 16 pass | |
| 17 | |
| 18 | |
| 19 class Serialization(object): | |
| 20 """ | |
| 21 Helper class to serialize/deserialize a struct. | |
| 22 """ | |
| 23 def __init__(self, groups): | |
| 24 self._groups = groups | |
| 25 self.version = _GetVersion(groups) | |
| 26 main_struct = _GetStruct(groups) | |
| 27 self.size = HEADER_STRUCT.size + main_struct.size | |
| 28 self._struct_per_version = { | |
| 29 self.version: main_struct, | |
| 30 } | |
| 31 | |
| 32 def _GetMainStruct(self): | |
| 33 return self._GetStruct(self.version) | |
| 34 | |
| 35 def _GetStruct(self, version): | |
| 36 # If asking for a greater ver | |
| 37 version = min(version, self.version) | |
| 38 if version not in self._struct_per_version: | |
| 39 self._struct_per_version[version] = _GetStruct(_FilterGroups(self._groups, | |
| 40 version)) | |
| 41 return self._struct_per_version[version] | |
| 42 | |
| 43 def Serialize(self, obj, handle_offset): | |
| 44 """ | |
| 45 Serialize the given obj. handle_offset is the the first value to use when | |
| 46 encoding handles. | |
| 47 """ | |
| 48 handles = [] | |
| 49 data = bytearray(self.size) | |
| 50 HEADER_STRUCT.pack_into(data, 0, self.size, self.version) | |
| 51 position = HEADER_STRUCT.size | |
| 52 to_pack = [] | |
| 53 for group in self._groups: | |
| 54 position = position + NeededPaddingForAlignment(position, | |
| 55 group.GetByteSize()) | |
| 56 (entry, new_handles) = group.Serialize( | |
| 57 obj, | |
| 58 len(data) - position, | |
| 59 data, | |
| 60 handle_offset + len(handles)) | |
| 61 to_pack.append(entry) | |
| 62 handles.extend(new_handles) | |
| 63 position = position + group.GetByteSize() | |
| 64 self._GetMainStruct().pack_into(data, HEADER_STRUCT.size, *to_pack) | |
| 65 return (data, handles) | |
| 66 | |
| 67 | |
| 68 def NeededPaddingForAlignment(value, alignment=8): | |
| 69 """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.
| |
| 70 if value % alignment: | |
| 71 return alignment - (value % alignment) | |
| 72 return 0 | |
| 73 | |
| 74 | |
| 75 def _GetVersion(groups): | |
| 76 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.
| |
| 77 | |
| 78 | |
| 79 def _FilterGroups(groups, version): | |
| 80 return [group for group in groups if group.version < version] | |
| 81 | |
| 82 | |
| 83 def _GetStruct(groups): | |
| 84 index = 0 | |
| 85 codes = [ '=' ] | |
| 86 for group in groups: | |
| 87 code = group.GetTypeCode() | |
| 88 size = group.GetByteSize() | |
| 89 needed_padding = NeededPaddingForAlignment(index, size) | |
| 90 if needed_padding: | |
| 91 codes.append('x' * needed_padding) | |
| 92 index = index + needed_padding | |
| 93 codes.append(code) | |
| 94 index = index + size | |
| 95 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.
| |
| 96 if end_alignment: | |
| 97 codes.append('x' * (8 - end_alignment)) | |
| 98 return struct.Struct(''.join(codes)) | |
| OLD | NEW |