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 |