OLD | NEW |
| (Empty) |
1 # Copyright 2013 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 # This module's classes provide an interface to mojo modules. Modules are | |
6 # collections of interfaces and structs to be used by mojo ipc clients and | |
7 # servers. | |
8 # | |
9 # A simple interface would be created this way: | |
10 # module = mojom.generate.module.Module('Foo') | |
11 # interface = module.AddInterface('Bar') | |
12 # method = interface.AddMethod('Tat', 0) | |
13 # method.AddParameter('baz', 0, mojom.INT32) | |
14 | |
15 | |
16 class Kind(object): | |
17 def __init__(self, spec=None): | |
18 self.spec = spec | |
19 self.parent_kind = None | |
20 | |
21 | |
22 class ReferenceKind(Kind): | |
23 """ReferenceKind represents pointer types and handle types. | |
24 A type is nullable if null (for pointer types) or invalid handle (for handle | |
25 types) is a legal value for the type. | |
26 """ | |
27 | |
28 def __init__(self, spec=None, is_nullable=False): | |
29 assert spec is None or is_nullable == spec.startswith('?') | |
30 Kind.__init__(self, spec) | |
31 self.is_nullable = is_nullable | |
32 self.shared_definition = {} | |
33 | |
34 def MakeNullableKind(self): | |
35 assert not self.is_nullable | |
36 | |
37 if self == STRING: | |
38 return NULLABLE_STRING | |
39 if self == HANDLE: | |
40 return NULLABLE_HANDLE | |
41 if self == DCPIPE: | |
42 return NULLABLE_DCPIPE | |
43 if self == DPPIPE: | |
44 return NULLABLE_DPPIPE | |
45 if self == MSGPIPE: | |
46 return NULLABLE_MSGPIPE | |
47 if self == SHAREDBUFFER: | |
48 return NULLABLE_SHAREDBUFFER | |
49 | |
50 nullable_kind = type(self)() | |
51 nullable_kind.shared_definition = self.shared_definition | |
52 if self.spec is not None: | |
53 nullable_kind.spec = '?' + self.spec | |
54 nullable_kind.is_nullable = True | |
55 | |
56 return nullable_kind | |
57 | |
58 @classmethod | |
59 def AddSharedProperty(cls, name): | |
60 """Adds a property |name| to |cls|, which accesses the corresponding item in | |
61 |shared_definition|. | |
62 | |
63 The reason of adding such indirection is to enable sharing definition | |
64 between a reference kind and its nullable variation. For example: | |
65 a = Struct('test_struct_1') | |
66 b = a.MakeNullableKind() | |
67 a.name = 'test_struct_2' | |
68 print b.name # Outputs 'test_struct_2'. | |
69 """ | |
70 def Get(self): | |
71 return self.shared_definition[name] | |
72 | |
73 def Set(self, value): | |
74 self.shared_definition[name] = value | |
75 | |
76 setattr(cls, name, property(Get, Set)) | |
77 | |
78 | |
79 # Initialize the set of primitive types. These can be accessed by clients. | |
80 BOOL = Kind('b') | |
81 INT8 = Kind('i8') | |
82 INT16 = Kind('i16') | |
83 INT32 = Kind('i32') | |
84 INT64 = Kind('i64') | |
85 UINT8 = Kind('u8') | |
86 UINT16 = Kind('u16') | |
87 UINT32 = Kind('u32') | |
88 UINT64 = Kind('u64') | |
89 FLOAT = Kind('f') | |
90 DOUBLE = Kind('d') | |
91 STRING = ReferenceKind('s') | |
92 HANDLE = ReferenceKind('h') | |
93 DCPIPE = ReferenceKind('h:d:c') | |
94 DPPIPE = ReferenceKind('h:d:p') | |
95 MSGPIPE = ReferenceKind('h:m') | |
96 SHAREDBUFFER = ReferenceKind('h:s') | |
97 NULLABLE_STRING = ReferenceKind('?s', True) | |
98 NULLABLE_HANDLE = ReferenceKind('?h', True) | |
99 NULLABLE_DCPIPE = ReferenceKind('?h:d:c', True) | |
100 NULLABLE_DPPIPE = ReferenceKind('?h:d:p', True) | |
101 NULLABLE_MSGPIPE = ReferenceKind('?h:m', True) | |
102 NULLABLE_SHAREDBUFFER = ReferenceKind('?h:s', True) | |
103 | |
104 | |
105 # Collection of all Primitive types | |
106 PRIMITIVES = ( | |
107 BOOL, | |
108 INT8, | |
109 INT16, | |
110 INT32, | |
111 INT64, | |
112 UINT8, | |
113 UINT16, | |
114 UINT32, | |
115 UINT64, | |
116 FLOAT, | |
117 DOUBLE, | |
118 STRING, | |
119 HANDLE, | |
120 DCPIPE, | |
121 DPPIPE, | |
122 MSGPIPE, | |
123 SHAREDBUFFER, | |
124 NULLABLE_STRING, | |
125 NULLABLE_HANDLE, | |
126 NULLABLE_DCPIPE, | |
127 NULLABLE_DPPIPE, | |
128 NULLABLE_MSGPIPE, | |
129 NULLABLE_SHAREDBUFFER | |
130 ) | |
131 | |
132 | |
133 class NamedValue(object): | |
134 def __init__(self, module=None, parent_kind=None, name=None): | |
135 self.module = module | |
136 if module: | |
137 self.namespace = module.namespace | |
138 self.parent_kind = parent_kind | |
139 self.name = name | |
140 self.imported_from = None | |
141 | |
142 def GetSpec(self): | |
143 return (self.namespace + '.' + | |
144 (self.parent_kind and (self.parent_kind.name + '.') or "") + | |
145 self.name) | |
146 | |
147 | |
148 class BuiltinValue(object): | |
149 def __init__(self, value): | |
150 self.value = value | |
151 | |
152 | |
153 class ConstantValue(NamedValue): | |
154 def __init__(self, module=None, parent_kind=None, constant=None): | |
155 if constant: | |
156 NamedValue.__init__(self, module, parent_kind, constant.name) | |
157 else: | |
158 NamedValue.__init__(self, module, parent_kind) | |
159 self.constant = constant | |
160 | |
161 | |
162 class EnumValue(NamedValue): | |
163 def __init__(self, module=None, enum=None, field=None): | |
164 if enum and field: | |
165 NamedValue.__init__(self, module, enum.parent_kind, field.name) | |
166 else: | |
167 NamedValue.__init__(self, module) | |
168 self.enum = enum | |
169 | |
170 def GetSpec(self): | |
171 return (self.namespace + '.' + | |
172 (self.parent_kind and (self.parent_kind.name + '.') or "") + | |
173 self.enum.name + '.' + self.name) | |
174 | |
175 | |
176 class Constant(object): | |
177 def __init__(self, name=None, kind=None, value=None, parent_kind=None): | |
178 self.name = name | |
179 self.kind = kind | |
180 self.value = value | |
181 self.parent_kind = parent_kind | |
182 | |
183 | |
184 class Field(object): | |
185 def __init__(self, name=None, kind=None, ordinal=None, default=None, | |
186 attributes=None): | |
187 if self.__class__.__name__ == 'Field': | |
188 raise Exception() | |
189 self.name = name | |
190 self.kind = kind | |
191 self.ordinal = ordinal | |
192 self.default = default | |
193 self.attributes = attributes | |
194 | |
195 | |
196 class StructField(Field): pass | |
197 | |
198 | |
199 class UnionField(Field): pass | |
200 | |
201 | |
202 class Struct(ReferenceKind): | |
203 ReferenceKind.AddSharedProperty('name') | |
204 ReferenceKind.AddSharedProperty('module') | |
205 ReferenceKind.AddSharedProperty('imported_from') | |
206 ReferenceKind.AddSharedProperty('fields') | |
207 ReferenceKind.AddSharedProperty('attributes') | |
208 ReferenceKind.AddSharedProperty('constants') | |
209 ReferenceKind.AddSharedProperty('enums') | |
210 ReferenceKind.AddSharedProperty('type_key') | |
211 | |
212 def __init__(self, name=None, module=None, attributes=None): | |
213 if name is not None: | |
214 spec = 'x:' + name | |
215 else: | |
216 spec = None | |
217 ReferenceKind.__init__(self, spec) | |
218 self.name = name | |
219 self.module = module | |
220 self.imported_from = None | |
221 self.fields = [] | |
222 self.constants = [] | |
223 self.enums = [] | |
224 self.attributes = attributes | |
225 | |
226 def AddField(self, name, kind, ordinal=None, default=None, attributes=None): | |
227 field = StructField(name, kind, ordinal, default, attributes) | |
228 self.fields.append(field) | |
229 return field | |
230 | |
231 | |
232 class Union(ReferenceKind): | |
233 ReferenceKind.AddSharedProperty('name') | |
234 ReferenceKind.AddSharedProperty('module') | |
235 ReferenceKind.AddSharedProperty('imported_from') | |
236 ReferenceKind.AddSharedProperty('fields') | |
237 ReferenceKind.AddSharedProperty('attributes') | |
238 ReferenceKind.AddSharedProperty('type_key') | |
239 | |
240 def __init__(self, name=None, module=None, attributes=None): | |
241 if name is not None: | |
242 spec = 'x:' + name | |
243 else: | |
244 spec = None | |
245 ReferenceKind.__init__(self, spec) | |
246 self.name = name | |
247 self.module = module | |
248 self.imported_from = None | |
249 self.fields = [] | |
250 self.attributes = attributes | |
251 | |
252 def AddField(self, name, kind, ordinal=None, attributes=None): | |
253 field = UnionField(name, kind, ordinal, None, attributes) | |
254 self.fields.append(field) | |
255 return field | |
256 | |
257 | |
258 class Array(ReferenceKind): | |
259 ReferenceKind.AddSharedProperty('kind') | |
260 ReferenceKind.AddSharedProperty('length') | |
261 | |
262 def __init__(self, kind=None, length=None): | |
263 if kind is not None: | |
264 if length is not None: | |
265 spec = 'a%d:%s' % (length, kind.spec) | |
266 else: | |
267 spec = 'a:%s' % kind.spec | |
268 | |
269 ReferenceKind.__init__(self, spec) | |
270 else: | |
271 ReferenceKind.__init__(self) | |
272 self.kind = kind | |
273 self.length = length | |
274 | |
275 | |
276 class Map(ReferenceKind): | |
277 ReferenceKind.AddSharedProperty('key_kind') | |
278 ReferenceKind.AddSharedProperty('value_kind') | |
279 | |
280 def __init__(self, key_kind=None, value_kind=None): | |
281 if (key_kind is not None and value_kind is not None): | |
282 ReferenceKind.__init__(self, | |
283 'm[' + key_kind.spec + '][' + value_kind.spec + | |
284 ']') | |
285 if IsNullableKind(key_kind): | |
286 raise Exception("Nullable kinds cannot be keys in maps.") | |
287 if IsStructKind(key_kind): | |
288 # TODO(erg): It would sometimes be nice if we could key on struct | |
289 # values. However, what happens if the struct has a handle in it? Or | |
290 # non-copyable data like an array? | |
291 raise Exception("Structs cannot be keys in maps.") | |
292 if IsAnyHandleKind(key_kind): | |
293 raise Exception("Handles cannot be keys in maps.") | |
294 if IsInterfaceKind(key_kind): | |
295 raise Exception("Interfaces cannot be keys in maps.") | |
296 if IsArrayKind(key_kind): | |
297 raise Exception("Arrays cannot be keys in maps.") | |
298 else: | |
299 ReferenceKind.__init__(self) | |
300 | |
301 self.key_kind = key_kind | |
302 self.value_kind = value_kind | |
303 | |
304 | |
305 class InterfaceRequest(ReferenceKind): | |
306 ReferenceKind.AddSharedProperty('kind') | |
307 | |
308 def __init__(self, kind=None): | |
309 if kind is not None: | |
310 if not isinstance(kind, Interface): | |
311 raise Exception( | |
312 "Interface request requires %r to be an interface." % kind.spec) | |
313 ReferenceKind.__init__(self, 'r:' + kind.spec) | |
314 else: | |
315 ReferenceKind.__init__(self) | |
316 self.kind = kind | |
317 | |
318 | |
319 class Parameter(object): | |
320 def __init__(self, name=None, kind=None, ordinal=None, default=None, | |
321 attributes=None): | |
322 self.name = name | |
323 self.ordinal = ordinal | |
324 self.kind = kind | |
325 self.default = default | |
326 self.attributes = attributes | |
327 | |
328 | |
329 class Method(object): | |
330 def __init__(self, interface, name, ordinal=None, attributes=None): | |
331 self.interface = interface | |
332 self.name = name | |
333 self.ordinal = ordinal | |
334 self.parameters = [] | |
335 self.response_parameters = None | |
336 self.attributes = attributes | |
337 | |
338 def AddParameter(self, name, kind, ordinal=None, default=None, | |
339 attributes=None): | |
340 parameter = Parameter(name, kind, ordinal, default, attributes) | |
341 self.parameters.append(parameter) | |
342 return parameter | |
343 | |
344 def AddResponseParameter(self, name, kind, ordinal=None, default=None, | |
345 attributes=None): | |
346 if self.response_parameters == None: | |
347 self.response_parameters = [] | |
348 parameter = Parameter(name, kind, ordinal, default, attributes) | |
349 self.response_parameters.append(parameter) | |
350 return parameter | |
351 | |
352 | |
353 class Interface(ReferenceKind): | |
354 ReferenceKind.AddSharedProperty('module') | |
355 ReferenceKind.AddSharedProperty('name') | |
356 ReferenceKind.AddSharedProperty('imported_from') | |
357 ReferenceKind.AddSharedProperty('methods') | |
358 ReferenceKind.AddSharedProperty('attributes') | |
359 ReferenceKind.AddSharedProperty('constants') | |
360 ReferenceKind.AddSharedProperty('enums') | |
361 ReferenceKind.AddSharedProperty('type_key') | |
362 | |
363 def __init__(self, name=None, module=None, attributes=None): | |
364 if name is not None: | |
365 spec = 'x:' + name | |
366 else: | |
367 spec = None | |
368 ReferenceKind.__init__(self, spec) | |
369 self.module = module | |
370 self.name = name | |
371 self.imported_from = None | |
372 self.methods = [] | |
373 self.enums = [] | |
374 self.constants = [] | |
375 self.attributes = attributes | |
376 | |
377 def AddMethod(self, name, ordinal=None, attributes=None): | |
378 method = Method(self, name, ordinal, attributes) | |
379 self.methods.append(method) | |
380 return method | |
381 | |
382 # TODO(451323): Remove when the language backends no longer rely on this. | |
383 @property | |
384 def client(self): | |
385 return None | |
386 | |
387 | |
388 class EnumField(object): | |
389 def __init__(self, name=None, value=None, attributes=None, | |
390 numeric_value=None): | |
391 self.name = name | |
392 self.value = value | |
393 self.attributes = attributes | |
394 self.numeric_value = numeric_value | |
395 | |
396 | |
397 class Enum(Kind): | |
398 def __init__(self, name=None, module=None, attributes=None): | |
399 self.module = module | |
400 self.name = name | |
401 self.imported_from = None | |
402 if name is not None: | |
403 spec = 'x:' + name | |
404 else: | |
405 spec = None | |
406 Kind.__init__(self, spec) | |
407 self.fields = [] | |
408 self.attributes = attributes | |
409 | |
410 | |
411 class Module(object): | |
412 def __init__(self, name=None, namespace=None, attributes=None): | |
413 self.name = name | |
414 self.path = name | |
415 self.namespace = namespace | |
416 self.structs = [] | |
417 self.unions = [] | |
418 self.interfaces = [] | |
419 self.enums = [] | |
420 self.constants = [] | |
421 self.kinds = {} | |
422 self.attributes = attributes | |
423 self.imports = [] | |
424 # Transitive imports should contain all of the module's imports plus | |
425 # all of their imports recursively. | |
426 self.transitive_imports = [] | |
427 | |
428 def AddInterface(self, name, attributes=None): | |
429 interface = Interface(name, self, attributes) | |
430 self.interfaces.append(interface) | |
431 return interface | |
432 | |
433 def AddStruct(self, name, attributes=None): | |
434 struct = Struct(name, self, attributes) | |
435 self.structs.append(struct) | |
436 return struct | |
437 | |
438 def AddUnion(self, name, attributes=None): | |
439 union = Union(name, self, attributes) | |
440 self.unions.append(union) | |
441 return union | |
442 | |
443 def GetPackageName(kind): | |
444 """Get the package name from the given kind's module.""" | |
445 return kind.module.name.split('.')[0] | |
446 | |
447 def IsBoolKind(kind): | |
448 return kind.spec == BOOL.spec | |
449 | |
450 | |
451 def IsFloatKind(kind): | |
452 return kind.spec == FLOAT.spec | |
453 | |
454 | |
455 def IsDoubleKind(kind): | |
456 return kind.spec == DOUBLE.spec | |
457 | |
458 | |
459 def IsIntegralKind(kind): | |
460 return (kind.spec == BOOL.spec or | |
461 kind.spec == INT8.spec or | |
462 kind.spec == INT16.spec or | |
463 kind.spec == INT32.spec or | |
464 kind.spec == INT64.spec or | |
465 kind.spec == UINT8.spec or | |
466 kind.spec == UINT16.spec or | |
467 kind.spec == UINT32.spec or | |
468 kind.spec == UINT64.spec) | |
469 | |
470 def IsNumericalKind(kind): | |
471 return (IsBoolKind(kind) or | |
472 IsFloatKind(kind) or | |
473 IsDoubleKind(kind) or | |
474 IsIntegralKind(kind)) | |
475 | |
476 def IsStringKind(kind): | |
477 return kind.spec == STRING.spec or kind.spec == NULLABLE_STRING.spec | |
478 | |
479 | |
480 def IsGenericHandleKind(kind): | |
481 return kind.spec == HANDLE.spec or kind.spec == NULLABLE_HANDLE.spec | |
482 | |
483 | |
484 def IsDataPipeConsumerKind(kind): | |
485 return kind.spec == DCPIPE.spec or kind.spec == NULLABLE_DCPIPE.spec | |
486 | |
487 | |
488 def IsDataPipeProducerKind(kind): | |
489 return kind.spec == DPPIPE.spec or kind.spec == NULLABLE_DPPIPE.spec | |
490 | |
491 | |
492 def IsMessagePipeKind(kind): | |
493 return kind.spec == MSGPIPE.spec or kind.spec == NULLABLE_MSGPIPE.spec | |
494 | |
495 | |
496 def IsSharedBufferKind(kind): | |
497 return (kind.spec == SHAREDBUFFER.spec or | |
498 kind.spec == NULLABLE_SHAREDBUFFER.spec) | |
499 | |
500 | |
501 def IsStructKind(kind): | |
502 return isinstance(kind, Struct) | |
503 | |
504 | |
505 def IsUnionKind(kind): | |
506 return isinstance(kind, Union) | |
507 | |
508 | |
509 def IsArrayKind(kind): | |
510 return isinstance(kind, Array) | |
511 | |
512 | |
513 def IsInterfaceKind(kind): | |
514 return isinstance(kind, Interface) | |
515 | |
516 | |
517 def IsInterfaceRequestKind(kind): | |
518 return isinstance(kind, InterfaceRequest) | |
519 | |
520 | |
521 def IsEnumKind(kind): | |
522 return isinstance(kind, Enum) | |
523 | |
524 | |
525 def IsReferenceKind(kind): | |
526 return isinstance(kind, ReferenceKind) | |
527 | |
528 | |
529 def IsNullableKind(kind): | |
530 return IsReferenceKind(kind) and kind.is_nullable | |
531 | |
532 | |
533 def IsMapKind(kind): | |
534 return isinstance(kind, Map) | |
535 | |
536 | |
537 def IsObjectKind(kind): | |
538 return IsPointerKind(kind) or IsUnionKind(kind) | |
539 | |
540 | |
541 def IsPointerKind(kind): | |
542 return (IsStructKind(kind) or IsArrayKind(kind) or IsStringKind(kind) or | |
543 IsMapKind(kind)) | |
544 | |
545 | |
546 # Please note that interface is not considered as handle kind, since it is an | |
547 # aggregate type consisting of a handle and a version number. | |
548 def IsAnyHandleKind(kind): | |
549 return (IsGenericHandleKind(kind) or | |
550 IsDataPipeConsumerKind(kind) or | |
551 IsDataPipeProducerKind(kind) or | |
552 IsMessagePipeKind(kind) or | |
553 IsSharedBufferKind(kind) or | |
554 IsInterfaceRequestKind(kind)) | |
555 | |
556 | |
557 def IsMoveOnlyKind(kind): | |
558 return (not IsStringKind(kind) and IsObjectKind(kind)) or \ | |
559 IsAnyHandleKind(kind) or IsInterfaceKind(kind) | |
560 | |
561 | |
562 def ContainsHandles(kind, visited_kinds): | |
563 if kind in visited_kinds: | |
564 # No need to examine the kind again. | |
565 return False | |
566 visited_kinds.add(kind) | |
567 if IsAnyHandleKind(kind) or IsInterfaceKind(kind): | |
568 return True | |
569 if IsArrayKind(kind): | |
570 return ContainsHandles(kind.kind, visited_kinds) | |
571 if IsStructKind(kind) or IsUnionKind(kind): | |
572 for field in kind.fields: | |
573 if ContainsHandles(field.kind, visited_kinds): | |
574 return True | |
575 if IsMapKind(kind): | |
576 # No need to examine the key kind, only primitive kinds and non-nullable | |
577 # string are allowed to be key kinds. | |
578 return ContainsHandles(kind.value_kind, visited_kinds) | |
579 return False | |
580 | |
581 | |
582 def IsCloneableKind(kind): | |
583 return not ContainsHandles(kind, set()) | |
584 | |
585 | |
586 def HasCallbacks(interface): | |
587 for method in interface.methods: | |
588 if method.response_parameters != None: | |
589 return True | |
590 return False | |
OLD | NEW |