| 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 """The metaclasses used by the mojo python bindings.""" | |
| 6 | |
| 7 import itertools | |
| 8 | |
| 9 # pylint: disable=F0401 | |
| 10 import mojo_bindings.serialization as serialization | |
| 11 | |
| 12 | |
| 13 class MojoEnumType(type): | |
| 14 """Meta class for enumerations. | |
| 15 | |
| 16 Usage: | |
| 17 class MyEnum(object): | |
| 18 __metaclass__ = MojoEnumType | |
| 19 VALUES = [ | |
| 20 ('A', 0), | |
| 21 'B', | |
| 22 ('C', 5), | |
| 23 ] | |
| 24 | |
| 25 This will define a enum with 3 values, 'A' = 0, 'B' = 1 and 'C' = 5. | |
| 26 """ | |
| 27 | |
| 28 def __new__(mcs, name, bases, dictionary): | |
| 29 dictionary['__slots__'] = () | |
| 30 dictionary['__new__'] = None | |
| 31 for value in dictionary.pop('VALUES', []): | |
| 32 if not isinstance(value, tuple): | |
| 33 raise ValueError('incorrect value: %r' % value) | |
| 34 key, enum_value = value | |
| 35 if isinstance(key, str) and isinstance(enum_value, int): | |
| 36 dictionary[key] = enum_value | |
| 37 else: | |
| 38 raise ValueError('incorrect value: %r' % value) | |
| 39 return type.__new__(mcs, name, bases, dictionary) | |
| 40 | |
| 41 def __setattr__(cls, key, value): | |
| 42 raise AttributeError('can\'t set attribute') | |
| 43 | |
| 44 def __delattr__(cls, key): | |
| 45 raise AttributeError('can\'t delete attribute') | |
| 46 | |
| 47 | |
| 48 class MojoStructType(type): | |
| 49 """Meta class for structs. | |
| 50 | |
| 51 Usage: | |
| 52 class MyStruct(object): | |
| 53 __metaclass__ = MojoStructType | |
| 54 DESCRIPTOR = { | |
| 55 'constants': { | |
| 56 'C1': 1, | |
| 57 'C2': 2, | |
| 58 }, | |
| 59 'enums': { | |
| 60 'ENUM1': [ | |
| 61 ('V1', 1), | |
| 62 'V2', | |
| 63 ], | |
| 64 'ENUM2': [ | |
| 65 ('V1', 1), | |
| 66 'V2', | |
| 67 ], | |
| 68 }, | |
| 69 'fields': [ | |
| 70 SingleFieldGroup('x', _descriptor.TYPE_INT32, 0, 0), | |
| 71 ], | |
| 72 } | |
| 73 | |
| 74 This will define an struct, with: | |
| 75 - 2 constants 'C1' and 'C2'; | |
| 76 - 2 enums 'ENUM1' and 'ENUM2', each of those having 2 values, 'V1' and | |
| 77 'V2'; | |
| 78 - 1 int32 field named 'x'. | |
| 79 """ | |
| 80 | |
| 81 def __new__(mcs, name, bases, dictionary): | |
| 82 dictionary['__slots__'] = ('_fields') | |
| 83 descriptor = dictionary.pop('DESCRIPTOR', {}) | |
| 84 | |
| 85 # Add constants | |
| 86 dictionary.update(descriptor.get('constants', {})) | |
| 87 | |
| 88 # Add enums | |
| 89 enums = descriptor.get('enums', {}) | |
| 90 for key in enums: | |
| 91 dictionary[key] = MojoEnumType(key, (object,), { 'VALUES': enums[key] }) | |
| 92 | |
| 93 # Add fields | |
| 94 groups = descriptor.get('fields', []) | |
| 95 | |
| 96 fields = list( | |
| 97 itertools.chain.from_iterable([group.descriptors for group in groups])) | |
| 98 fields.sort(key=lambda f: f.index) | |
| 99 for field in fields: | |
| 100 dictionary[field.name] = _BuildProperty(field) | |
| 101 | |
| 102 # Add init | |
| 103 dictionary['__init__'] = _StructInit(fields) | |
| 104 | |
| 105 # Add serialization method | |
| 106 serialization_object = serialization.Serialization(groups) | |
| 107 def Serialize(self, handle_offset=0): | |
| 108 return serialization_object.Serialize(self, handle_offset) | |
| 109 dictionary['Serialize'] = Serialize | |
| 110 | |
| 111 # pylint: disable=W0212 | |
| 112 def AsDict(self): | |
| 113 return self._fields | |
| 114 dictionary['AsDict'] = AsDict | |
| 115 | |
| 116 def Deserialize(cls, context): | |
| 117 result = cls.__new__(cls) | |
| 118 fields = {} | |
| 119 serialization_object.Deserialize(fields, context) | |
| 120 result._fields = fields | |
| 121 return result | |
| 122 dictionary['Deserialize'] = classmethod(Deserialize) | |
| 123 | |
| 124 dictionary['__eq__'] = _StructEq(fields) | |
| 125 dictionary['__ne__'] = _StructNe | |
| 126 | |
| 127 return type.__new__(mcs, name, bases, dictionary) | |
| 128 | |
| 129 # Prevent adding new attributes, or mutating constants. | |
| 130 def __setattr__(cls, key, value): | |
| 131 raise AttributeError('can\'t set attribute') | |
| 132 | |
| 133 # Prevent deleting constants. | |
| 134 def __delattr__(cls, key): | |
| 135 raise AttributeError('can\'t delete attribute') | |
| 136 | |
| 137 | |
| 138 class MojoUnionType(type): | |
| 139 | |
| 140 def __new__(mcs, name, bases, dictionary): | |
| 141 dictionary['__slots__'] = ('_cur_field', '_data') | |
| 142 descriptor = dictionary.pop('DESCRIPTOR', {}) | |
| 143 | |
| 144 fields = descriptor.get('fields', []) | |
| 145 def _BuildUnionProperty(field): | |
| 146 | |
| 147 # pylint: disable=W0212 | |
| 148 def Get(self): | |
| 149 if self._cur_field != field: | |
| 150 raise AttributeError('%s is not currently set' % field.name, | |
| 151 field.name, self._cur_field.name) | |
| 152 return self._data | |
| 153 | |
| 154 # pylint: disable=W0212 | |
| 155 def Set(self, value): | |
| 156 self._cur_field = field | |
| 157 self._data = field.field_type.Convert(value) | |
| 158 | |
| 159 return property(Get, Set) | |
| 160 | |
| 161 for field in fields: | |
| 162 dictionary[field.name] = _BuildUnionProperty(field) | |
| 163 | |
| 164 def UnionInit(self, **kwargs): | |
| 165 self.SetInternals(None, None) | |
| 166 items = kwargs.items() | |
| 167 if len(items) == 0: | |
| 168 return | |
| 169 | |
| 170 if len(items) > 1: | |
| 171 raise TypeError('only 1 member may be set on a union.') | |
| 172 | |
| 173 setattr(self, items[0][0], items[0][1]) | |
| 174 dictionary['__init__'] = UnionInit | |
| 175 | |
| 176 serializer = serialization.UnionSerializer(fields) | |
| 177 def SerializeUnionInline(self, handle_offset=0): | |
| 178 return serializer.SerializeInline(self, handle_offset) | |
| 179 dictionary['SerializeInline'] = SerializeUnionInline | |
| 180 | |
| 181 def SerializeUnion(self, handle_offset=0): | |
| 182 return serializer.Serialize(self, handle_offset) | |
| 183 dictionary['Serialize'] = SerializeUnion | |
| 184 | |
| 185 def DeserializeUnion(cls, context): | |
| 186 return serializer.Deserialize(context, cls) | |
| 187 dictionary['Deserialize'] = classmethod(DeserializeUnion) | |
| 188 | |
| 189 class Tags(object): | |
| 190 __metaclass__ = MojoEnumType | |
| 191 VALUES = [(field.name, field.index) for field in fields] | |
| 192 dictionary['Tags'] = Tags | |
| 193 | |
| 194 def GetTag(self): | |
| 195 return self._cur_field.index | |
| 196 dictionary['tag'] = property(GetTag, None) | |
| 197 | |
| 198 def GetData(self): | |
| 199 return self._data | |
| 200 dictionary['data'] = property(GetData, None) | |
| 201 | |
| 202 def IsUnknown(self): | |
| 203 return not self._cur_field | |
| 204 dictionary['IsUnknown'] = IsUnknown | |
| 205 | |
| 206 def UnionEq(self, other): | |
| 207 return ( | |
| 208 (type(self) is type(other)) | |
| 209 and (self.tag == other.tag) | |
| 210 and (self.data == other.data)) | |
| 211 dictionary['__eq__'] = UnionEq | |
| 212 | |
| 213 def UnionNe(self, other): | |
| 214 return not self.__eq__(other) | |
| 215 dictionary['__ne__'] = UnionNe | |
| 216 | |
| 217 def UnionStr(self): | |
| 218 return '<%s.%s(%s): %s>' % ( | |
| 219 self.__class__.__name__, | |
| 220 self._cur_field.name, | |
| 221 self.tag, | |
| 222 self.data) | |
| 223 dictionary['__str__'] = UnionStr | |
| 224 dictionary['__repr__'] = UnionStr | |
| 225 | |
| 226 def SetInternals(self, field, data): | |
| 227 self._cur_field = field | |
| 228 self._data = data | |
| 229 dictionary['SetInternals'] = SetInternals | |
| 230 | |
| 231 | |
| 232 return type.__new__(mcs, name, bases, dictionary) | |
| 233 | |
| 234 | |
| 235 class InterfaceRequest(object): | |
| 236 """ | |
| 237 An interface request allows to send a request for an interface to a remote | |
| 238 object and start using it immediately. | |
| 239 """ | |
| 240 | |
| 241 def __init__(self, handle): | |
| 242 self._handle = handle | |
| 243 | |
| 244 def IsPending(self): | |
| 245 return self._handle.IsValid() | |
| 246 | |
| 247 def PassMessagePipe(self): | |
| 248 result = self._handle | |
| 249 self._handle = None | |
| 250 return result | |
| 251 | |
| 252 def Bind(self, impl): | |
| 253 type(impl).manager.Bind(impl, self.PassMessagePipe()) | |
| 254 | |
| 255 | |
| 256 class InterfaceProxy(object): | |
| 257 """ | |
| 258 A proxy allows to access a remote interface through a message pipe. | |
| 259 """ | |
| 260 pass | |
| 261 | |
| 262 | |
| 263 def _StructInit(fields): | |
| 264 def _Init(self, *args, **kwargs): | |
| 265 if len(args) + len(kwargs) > len(fields): | |
| 266 raise TypeError('__init__() takes %d argument (%d given)' % | |
| 267 (len(fields), len(args) + len(kwargs))) | |
| 268 self._fields = {} | |
| 269 for f, a in zip(fields, args): | |
| 270 self.__setattr__(f.name, a) | |
| 271 remaining_fields = set(x.name for x in fields[len(args):]) | |
| 272 for name in kwargs: | |
| 273 if not name in remaining_fields: | |
| 274 if name in (x.name for x in fields[:len(args)]): | |
| 275 raise TypeError( | |
| 276 '__init__() got multiple values for keyword argument %r' % name) | |
| 277 raise TypeError('__init__() got an unexpected keyword argument %r' % | |
| 278 name) | |
| 279 self.__setattr__(name, kwargs[name]) | |
| 280 return _Init | |
| 281 | |
| 282 | |
| 283 def _BuildProperty(field): | |
| 284 """Build the property for the given field.""" | |
| 285 | |
| 286 # pylint: disable=W0212 | |
| 287 def Get(self): | |
| 288 if field.name not in self._fields: | |
| 289 self._fields[field.name] = field.GetDefaultValue() | |
| 290 return self._fields[field.name] | |
| 291 | |
| 292 # pylint: disable=W0212 | |
| 293 def Set(self, value): | |
| 294 self._fields[field.name] = field.field_type.Convert(value) | |
| 295 | |
| 296 return property(Get, Set) | |
| 297 | |
| 298 | |
| 299 def _StructEq(fields): | |
| 300 def _Eq(self, other): | |
| 301 if type(self) is not type(other): | |
| 302 return False | |
| 303 for field in fields: | |
| 304 if getattr(self, field.name) != getattr(other, field.name): | |
| 305 return False | |
| 306 return True | |
| 307 return _Eq | |
| 308 | |
| 309 def _StructNe(self, other): | |
| 310 return not self.__eq__(other) | |
| OLD | NEW |