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# We use our own version of __repr__ when displaying the AST, as the 17# AST currently doesn't capture which nodes are reference (e.g. to 18# types) and which nodes are definitions. This allows us to e.g. print 19# the definition of a struct when it's defined inside a module, but 20# only print its name when it's referenced in e.g. a method parameter. 21def Repr(obj, as_ref=True): 22 """A version of __repr__ that can distinguish references. 23 24 Sometimes we like to print an object's full representation 25 (e.g. with its fields) and sometimes we just want to reference an 26 object that was printed in full elsewhere. This function allows us 27 to make that distinction. 28 29 Args: 30 obj: The object whose string representation we compute. 31 as_ref: If True, use the short reference representation. 32 33 Returns: 34 A str representation of |obj|. 35 """ 36 if hasattr(obj, 'Repr'): 37 return obj.Repr(as_ref=as_ref) 38 # Since we cannot implement Repr for existing container types, we 39 # handle them here. 40 elif isinstance(obj, list): 41 if not obj: 42 return '[]' 43 else: 44 return ('[\n%s\n]' % (',\n'.join(' %s' % Repr(elem, as_ref).replace( 45 '\n', '\n ') for elem in obj))) 46 elif isinstance(obj, dict): 47 if not obj: 48 return '{}' 49 else: 50 return ('{\n%s\n}' % (',\n'.join(' %s: %s' % ( 51 Repr(key, as_ref).replace('\n', '\n '), 52 Repr(val, as_ref).replace('\n', '\n ')) 53 for key, val in obj.iteritems()))) 54 else: 55 return repr(obj) 56 57 58def GenericRepr(obj, names): 59 """Compute generic Repr for |obj| based on the attributes in |names|. 60 61 Args: 62 obj: The object to compute a Repr for. 63 names: A dict from attribute names to include, to booleans 64 specifying whether those attributes should be shown as 65 references or not. 66 67 Returns: 68 A str representation of |obj|. 69 """ 70 def ReprIndent(name, as_ref): 71 return ' %s=%s' % (name, Repr(getattr(obj, name), as_ref).replace( 72 '\n', '\n ')) 73 74 return '%s(\n%s\n)' % ( 75 obj.__class__.__name__, 76 ',\n'.join(ReprIndent(name, as_ref) 77 for (name, as_ref) in names.iteritems())) 78 79 80class Kind(object): 81 """Kind represents a type (e.g. int8, string). 82 83 Attributes: 84 spec: A string uniquely identifying the type. May be None. 85 parent_kind: The enclosing type. For example, a struct defined 86 inside an interface has that interface as its parent. May be None. 87 """ 88 def __init__(self, spec=None): 89 self.spec = spec 90 self.parent_kind = None 91 92 def Repr(self, as_ref=True): 93 return '<%s spec=%r>' % (self.__class__.__name__, self.spec) 94 95 def __repr__(self): 96 # Gives us a decent __repr__ for all kinds. 97 return self.Repr() 98 99 100class ReferenceKind(Kind): 101 """ReferenceKind represents pointer and handle types. 102 103 A type is nullable if null (for pointer types) or invalid handle (for handle 104 types) is a legal value for the type. 105 106 Attributes: 107 is_nullable: True if the type is nullable. 108 """ 109 110 def __init__(self, spec=None, is_nullable=False): 111 assert spec is None or is_nullable == spec.startswith('?') 112 Kind.__init__(self, spec) 113 self.is_nullable = is_nullable 114 self.shared_definition = {} 115 116 def Repr(self, as_ref=True): 117 return '<%s spec=%r is_nullable=%r>' % (self.__class__.__name__, self.spec, 118 self.is_nullable) 119 120 def MakeNullableKind(self): 121 assert not self.is_nullable 122 123 if self == STRING: 124 return NULLABLE_STRING 125 if self == HANDLE: 126 return NULLABLE_HANDLE 127 if self == DCPIPE: 128 return NULLABLE_DCPIPE 129 if self == DPPIPE: 130 return NULLABLE_DPPIPE 131 if self == MSGPIPE: 132 return NULLABLE_MSGPIPE 133 if self == SHAREDBUFFER: 134 return NULLABLE_SHAREDBUFFER 135 136 nullable_kind = type(self)() 137 nullable_kind.shared_definition = self.shared_definition 138 if self.spec is not None: 139 nullable_kind.spec = '?' + self.spec 140 nullable_kind.is_nullable = True 141 142 return nullable_kind 143 144 @classmethod 145 def AddSharedProperty(cls, name): 146 """Adds a property |name| to |cls|, which accesses the corresponding item in 147 |shared_definition|. 148 149 The reason of adding such indirection is to enable sharing definition 150 between a reference kind and its nullable variation. For example: 151 a = Struct('test_struct_1') 152 b = a.MakeNullableKind() 153 a.name = 'test_struct_2' 154 print b.name # Outputs 'test_struct_2'. 155 """ 156 def Get(self): 157 return self.shared_definition[name] 158 159 def Set(self, value): 160 self.shared_definition[name] = value 161 162 setattr(cls, name, property(Get, Set)) 163 164 165# Initialize the set of primitive types. These can be accessed by clients. 166BOOL = Kind('b') 167INT8 = Kind('i8') 168INT16 = Kind('i16') 169INT32 = Kind('i32') 170INT64 = Kind('i64') 171UINT8 = Kind('u8') 172UINT16 = Kind('u16') 173UINT32 = Kind('u32') 174UINT64 = Kind('u64') 175FLOAT = Kind('f') 176DOUBLE = Kind('d') 177STRING = ReferenceKind('s') 178HANDLE = ReferenceKind('h') 179DCPIPE = ReferenceKind('h:d:c') 180DPPIPE = ReferenceKind('h:d:p') 181MSGPIPE = ReferenceKind('h:m') 182SHAREDBUFFER = ReferenceKind('h:s') 183NULLABLE_STRING = ReferenceKind('?s', True) 184NULLABLE_HANDLE = ReferenceKind('?h', True) 185NULLABLE_DCPIPE = ReferenceKind('?h:d:c', True) 186NULLABLE_DPPIPE = ReferenceKind('?h:d:p', True) 187NULLABLE_MSGPIPE = ReferenceKind('?h:m', True) 188NULLABLE_SHAREDBUFFER = ReferenceKind('?h:s', True) 189 190 191# Collection of all Primitive types 192PRIMITIVES = ( 193 BOOL, 194 INT8, 195 INT16, 196 INT32, 197 INT64, 198 UINT8, 199 UINT16, 200 UINT32, 201 UINT64, 202 FLOAT, 203 DOUBLE, 204 STRING, 205 HANDLE, 206 DCPIPE, 207 DPPIPE, 208 MSGPIPE, 209 SHAREDBUFFER, 210 NULLABLE_STRING, 211 NULLABLE_HANDLE, 212 NULLABLE_DCPIPE, 213 NULLABLE_DPPIPE, 214 NULLABLE_MSGPIPE, 215 NULLABLE_SHAREDBUFFER 216) 217 218 219ATTRIBUTE_MIN_VERSION = 'MinVersion' 220ATTRIBUTE_EXTENSIBLE = 'Extensible' 221ATTRIBUTE_SYNC = 'Sync' 222 223 224class NamedValue(object): 225 def __init__(self, module, parent_kind, name): 226 self.module = module 227 self.namespace = module.namespace 228 self.parent_kind = parent_kind 229 self.name = name 230 self.imported_from = None 231 232 def GetSpec(self): 233 return (self.namespace + '.' + 234 (self.parent_kind and (self.parent_kind.name + '.') or "") + 235 self.name) 236 237 238class BuiltinValue(object): 239 def __init__(self, value): 240 self.value = value 241 242 243class ConstantValue(NamedValue): 244 def __init__(self, module, parent_kind, constant): 245 NamedValue.__init__(self, module, parent_kind, constant.name) 246 self.constant = constant 247 248 249class EnumValue(NamedValue): 250 def __init__(self, module, enum, field): 251 NamedValue.__init__(self, module, enum.parent_kind, field.name) 252 self.enum = enum 253 254 def GetSpec(self): 255 return (self.namespace + '.' + 256 (self.parent_kind and (self.parent_kind.name + '.') or "") + 257 self.enum.name + '.' + self.name) 258 259 260class Constant(object): 261 def __init__(self, name=None, kind=None, value=None, parent_kind=None): 262 self.name = name 263 self.kind = kind 264 self.value = value 265 self.parent_kind = parent_kind 266 267 268class Field(object): 269 def __init__(self, name=None, kind=None, ordinal=None, default=None, 270 attributes=None): 271 if self.__class__.__name__ == 'Field': 272 raise Exception() 273 self.name = name 274 self.kind = kind 275 self.ordinal = ordinal 276 self.default = default 277 self.attributes = attributes 278 279 def Repr(self, as_ref=True): 280 # Fields are only referenced by objects which define them and thus 281 # they are always displayed as non-references. 282 return GenericRepr(self, {'name': False, 'kind': True}) 283 284 @property 285 def min_version(self): 286 return self.attributes.get(ATTRIBUTE_MIN_VERSION) \ 287 if self.attributes else None 288 289 290class StructField(Field): pass 291 292 293class UnionField(Field): pass 294 295 296class Struct(ReferenceKind): 297 """A struct with typed fields. 298 299 Attributes: 300 name: {str} The name of the struct type. 301 native_only: {bool} Does the struct have a body (i.e. any fields) or is it 302 purely a native struct. 303 module: {Module} The defining module. 304 imported_from: {dict} Information about where this union was 305 imported from. 306 fields: {List[StructField]} The members of the struct. 307 attributes: {dict} Additional information about the struct, such as 308 if it's a native struct. 309 """ 310 311 ReferenceKind.AddSharedProperty('name') 312 ReferenceKind.AddSharedProperty('native_only') 313 ReferenceKind.AddSharedProperty('module') 314 ReferenceKind.AddSharedProperty('imported_from') 315 ReferenceKind.AddSharedProperty('fields') 316 ReferenceKind.AddSharedProperty('attributes') 317 318 def __init__(self, name=None, module=None, attributes=None): 319 if name is not None: 320 spec = 'x:' + name 321 else: 322 spec = None 323 ReferenceKind.__init__(self, spec) 324 self.name = name 325 self.native_only = False 326 self.module = module 327 self.imported_from = None 328 self.fields = [] 329 self.attributes = attributes 330 331 def Repr(self, as_ref=True): 332 if as_ref: 333 return '<%s name=%r imported_from=%s>' % ( 334 self.__class__.__name__, self.name, 335 Repr(self.imported_from, as_ref=True)) 336 else: 337 return GenericRepr(self, {'name': False, 'fields': False, 338 'imported_from': True}) 339 340 def AddField(self, name, kind, ordinal=None, default=None, attributes=None): 341 field = StructField(name, kind, ordinal, default, attributes) 342 self.fields.append(field) 343 return field 344 345 346class Union(ReferenceKind): 347 """A union of several kinds. 348 349 Attributes: 350 name: {str} The name of the union type. 351 module: {Module} The defining module. 352 imported_from: {dict} Information about where this union was 353 imported from. 354 fields: {List[UnionField]} The members of the union. 355 attributes: {dict} Additional information about the union, such as 356 which Java class name to use to represent it in the generated 357 bindings. 358 """ 359 ReferenceKind.AddSharedProperty('name') 360 ReferenceKind.AddSharedProperty('module') 361 ReferenceKind.AddSharedProperty('imported_from') 362 ReferenceKind.AddSharedProperty('fields') 363 ReferenceKind.AddSharedProperty('attributes') 364 365 def __init__(self, name=None, module=None, attributes=None): 366 if name is not None: 367 spec = 'x:' + name 368 else: 369 spec = None 370 ReferenceKind.__init__(self, spec) 371 self.name = name 372 self.module = module 373 self.imported_from = None 374 self.fields = [] 375 self.attributes = attributes 376 377 def Repr(self, as_ref=True): 378 if as_ref: 379 return '<%s spec=%r is_nullable=%r fields=%s>' % ( 380 self.__class__.__name__, self.spec, self.is_nullable, 381 Repr(self.fields)) 382 else: 383 return GenericRepr(self, {'fields': True, 'is_nullable': False}) 384 385 def AddField(self, name, kind, ordinal=None, attributes=None): 386 field = UnionField(name, kind, ordinal, None, attributes) 387 self.fields.append(field) 388 return field 389 390 391class Array(ReferenceKind): 392 """An array. 393 394 Attributes: 395 kind: {Kind} The type of the elements. May be None. 396 length: The number of elements. None if unknown. 397 """ 398 399 ReferenceKind.AddSharedProperty('kind') 400 ReferenceKind.AddSharedProperty('length') 401 402 def __init__(self, kind=None, length=None): 403 if kind is not None: 404 if length is not None: 405 spec = 'a%d:%s' % (length, kind.spec) 406 else: 407 spec = 'a:%s' % kind.spec 408 409 ReferenceKind.__init__(self, spec) 410 else: 411 ReferenceKind.__init__(self) 412 self.kind = kind 413 self.length = length 414 415 def Repr(self, as_ref=True): 416 if as_ref: 417 return '<%s spec=%r is_nullable=%r kind=%s length=%r>' % ( 418 self.__class__.__name__, self.spec, self.is_nullable, Repr(self.kind), 419 self.length) 420 else: 421 return GenericRepr(self, {'kind': True, 'length': False, 422 'is_nullable': False}) 423 424 425class Map(ReferenceKind): 426 """A map. 427 428 Attributes: 429 key_kind: {Kind} The type of the keys. May be None. 430 value_kind: {Kind} The type of the elements. May be None. 431 """ 432 ReferenceKind.AddSharedProperty('key_kind') 433 ReferenceKind.AddSharedProperty('value_kind') 434 435 def __init__(self, key_kind=None, value_kind=None): 436 if (key_kind is not None and value_kind is not None): 437 ReferenceKind.__init__(self, 438 'm[' + key_kind.spec + '][' + value_kind.spec + 439 ']') 440 if IsNullableKind(key_kind): 441 raise Exception("Nullable kinds cannot be keys in maps.") 442 if IsAnyHandleKind(key_kind): 443 raise Exception("Handles cannot be keys in maps.") 444 if IsAnyInterfaceKind(key_kind): 445 raise Exception("Interfaces cannot be keys in maps.") 446 if IsArrayKind(key_kind): 447 raise Exception("Arrays cannot be keys in maps.") 448 else: 449 ReferenceKind.__init__(self) 450 451 self.key_kind = key_kind 452 self.value_kind = value_kind 453 454 def Repr(self, as_ref=True): 455 if as_ref: 456 return '<%s spec=%r is_nullable=%r key_kind=%s value_kind=%s>' % ( 457 self.__class__.__name__, self.spec, self.is_nullable, 458 Repr(self.key_kind), Repr(self.value_kind)) 459 else: 460 return GenericRepr(self, {'key_kind': True, 'value_kind': True}) 461 462 463class InterfaceRequest(ReferenceKind): 464 ReferenceKind.AddSharedProperty('kind') 465 466 def __init__(self, kind=None): 467 if kind is not None: 468 if not isinstance(kind, Interface): 469 raise Exception( 470 "Interface request requires %r to be an interface." % kind.spec) 471 ReferenceKind.__init__(self, 'r:' + kind.spec) 472 else: 473 ReferenceKind.__init__(self) 474 self.kind = kind 475 476 477class AssociatedInterfaceRequest(ReferenceKind): 478 ReferenceKind.AddSharedProperty('kind') 479 480 def __init__(self, kind=None): 481 if kind is not None: 482 if not isinstance(kind, InterfaceRequest): 483 raise Exception( 484 "Associated interface request requires %r to be an interface " 485 "request." % kind.spec) 486 assert not kind.is_nullable 487 ReferenceKind.__init__(self, 'asso:' + kind.spec) 488 else: 489 ReferenceKind.__init__(self) 490 self.kind = kind.kind if kind is not None else None 491 492 493class Parameter(object): 494 def __init__(self, name=None, kind=None, ordinal=None, default=None, 495 attributes=None): 496 self.name = name 497 self.ordinal = ordinal 498 self.kind = kind 499 self.default = default 500 self.attributes = attributes 501 502 def Repr(self, as_ref=True): 503 return '<%s name=%r kind=%s>' % (self.__class__.__name__, self.name, 504 self.kind.Repr(as_ref=True)) 505 506 @property 507 def min_version(self): 508 return self.attributes.get(ATTRIBUTE_MIN_VERSION) \ 509 if self.attributes else None 510 511 512class Method(object): 513 def __init__(self, interface, name, ordinal=None, attributes=None): 514 self.interface = interface 515 self.name = name 516 self.ordinal = ordinal 517 self.parameters = [] 518 self.response_parameters = None 519 self.attributes = attributes 520 521 def Repr(self, as_ref=True): 522 if as_ref: 523 return '<%s name=%r>' % (self.__class__.__name__, self.name) 524 else: 525 return GenericRepr(self, {'name': False, 'parameters': True, 526 'response_parameters': True}) 527 528 def AddParameter(self, name, kind, ordinal=None, default=None, 529 attributes=None): 530 parameter = Parameter(name, kind, ordinal, default, attributes) 531 self.parameters.append(parameter) 532 return parameter 533 534 def AddResponseParameter(self, name, kind, ordinal=None, default=None, 535 attributes=None): 536 if self.response_parameters == None: 537 self.response_parameters = [] 538 parameter = Parameter(name, kind, ordinal, default, attributes) 539 self.response_parameters.append(parameter) 540 return parameter 541 542 @property 543 def min_version(self): 544 return self.attributes.get(ATTRIBUTE_MIN_VERSION) \ 545 if self.attributes else None 546 547 @property 548 def sync(self): 549 return self.attributes.get(ATTRIBUTE_SYNC) \ 550 if self.attributes else None 551 552 553class Interface(ReferenceKind): 554 ReferenceKind.AddSharedProperty('module') 555 ReferenceKind.AddSharedProperty('name') 556 ReferenceKind.AddSharedProperty('imported_from') 557 ReferenceKind.AddSharedProperty('methods') 558 ReferenceKind.AddSharedProperty('attributes') 559 560 def __init__(self, name=None, module=None, attributes=None): 561 if name is not None: 562 spec = 'x:' + name 563 else: 564 spec = None 565 ReferenceKind.__init__(self, spec) 566 self.module = module 567 self.name = name 568 self.imported_from = None 569 self.methods = [] 570 self.attributes = attributes 571 572 def Repr(self, as_ref=True): 573 if as_ref: 574 return '<%s name=%r>' % (self.__class__.__name__, self.name) 575 else: 576 return GenericRepr(self, {'name': False, 'attributes': False, 577 'methods': False}) 578 579 def AddMethod(self, name, ordinal=None, attributes=None): 580 method = Method(self, name, ordinal, attributes) 581 self.methods.append(method) 582 return method 583 584 # TODO(451323): Remove when the language backends no longer rely on this. 585 @property 586 def client(self): 587 return None 588 589 590class AssociatedInterface(ReferenceKind): 591 ReferenceKind.AddSharedProperty('kind') 592 593 def __init__(self, kind=None): 594 if kind is not None: 595 if not isinstance(kind, Interface): 596 raise Exception( 597 "Associated interface requires %r to be an interface." % kind.spec) 598 assert not kind.is_nullable 599 ReferenceKind.__init__(self, 'asso:' + kind.spec) 600 else: 601 ReferenceKind.__init__(self) 602 self.kind = kind 603 604 605class EnumField(object): 606 def __init__(self, name=None, value=None, attributes=None, 607 numeric_value=None): 608 self.name = name 609 self.value = value 610 self.attributes = attributes 611 self.numeric_value = numeric_value 612 613 @property 614 def min_version(self): 615 return self.attributes.get(ATTRIBUTE_MIN_VERSION) \ 616 if self.attributes else None 617 618 619class Enum(Kind): 620 def __init__(self, name=None, module=None, attributes=None): 621 self.module = module 622 self.name = name 623 self.native_only = False 624 self.imported_from = None 625 if name is not None: 626 spec = 'x:' + name 627 else: 628 spec = None 629 Kind.__init__(self, spec) 630 self.fields = [] 631 self.attributes = attributes 632 633 def Repr(self, as_ref=True): 634 if as_ref: 635 return '<%s name=%r>' % (self.__class__.__name__, self.name) 636 else: 637 return GenericRepr(self, {'name': False, 'fields': False}) 638 639 @property 640 def extensible(self): 641 return self.attributes.get(ATTRIBUTE_EXTENSIBLE, False) \ 642 if self.attributes else False 643 644 645class Module(object): 646 def __init__(self, name=None, namespace=None, attributes=None): 647 self.name = name 648 self.path = name 649 self.namespace = namespace 650 self.structs = [] 651 self.unions = [] 652 self.interfaces = [] 653 self.kinds = {} 654 self.attributes = attributes 655 656 def __repr__(self): 657 # Gives us a decent __repr__ for modules. 658 return self.Repr() 659 660 def Repr(self, as_ref=True): 661 if as_ref: 662 return '<%s name=%r namespace=%r>' % ( 663 self.__class__.__name__, self.name, self.namespace) 664 else: 665 return GenericRepr(self, {'name': False, 'namespace': False, 666 'attributes': False, 'structs': False, 667 'interfaces': False, 'unions': False}) 668 669 def AddInterface(self, name, attributes=None): 670 interface = Interface(name, self, attributes) 671 self.interfaces.append(interface) 672 return interface 673 674 def AddStruct(self, name, attributes=None): 675 struct = Struct(name, self, attributes) 676 self.structs.append(struct) 677 return struct 678 679 def AddUnion(self, name, attributes=None): 680 union = Union(name, self, attributes) 681 self.unions.append(union) 682 return union 683 684 685def IsBoolKind(kind): 686 return kind.spec == BOOL.spec 687 688 689def IsFloatKind(kind): 690 return kind.spec == FLOAT.spec 691 692 693def IsDoubleKind(kind): 694 return kind.spec == DOUBLE.spec 695 696 697def IsIntegralKind(kind): 698 return (kind.spec == BOOL.spec or 699 kind.spec == INT8.spec or 700 kind.spec == INT16.spec or 701 kind.spec == INT32.spec or 702 kind.spec == INT64.spec or 703 kind.spec == UINT8.spec or 704 kind.spec == UINT16.spec or 705 kind.spec == UINT32.spec or 706 kind.spec == UINT64.spec) 707 708 709def IsStringKind(kind): 710 return kind.spec == STRING.spec or kind.spec == NULLABLE_STRING.spec 711 712 713def IsGenericHandleKind(kind): 714 return kind.spec == HANDLE.spec or kind.spec == NULLABLE_HANDLE.spec 715 716 717def IsDataPipeConsumerKind(kind): 718 return kind.spec == DCPIPE.spec or kind.spec == NULLABLE_DCPIPE.spec 719 720 721def IsDataPipeProducerKind(kind): 722 return kind.spec == DPPIPE.spec or kind.spec == NULLABLE_DPPIPE.spec 723 724 725def IsMessagePipeKind(kind): 726 return kind.spec == MSGPIPE.spec or kind.spec == NULLABLE_MSGPIPE.spec 727 728 729def IsSharedBufferKind(kind): 730 return (kind.spec == SHAREDBUFFER.spec or 731 kind.spec == NULLABLE_SHAREDBUFFER.spec) 732 733 734def IsStructKind(kind): 735 return isinstance(kind, Struct) 736 737 738def IsUnionKind(kind): 739 return isinstance(kind, Union) 740 741 742def IsArrayKind(kind): 743 return isinstance(kind, Array) 744 745 746def IsInterfaceKind(kind): 747 return isinstance(kind, Interface) 748 749 750def IsAssociatedInterfaceKind(kind): 751 return isinstance(kind, AssociatedInterface) 752 753 754def IsInterfaceRequestKind(kind): 755 return isinstance(kind, InterfaceRequest) 756 757 758def IsAssociatedInterfaceRequestKind(kind): 759 return isinstance(kind, AssociatedInterfaceRequest) 760 761 762def IsEnumKind(kind): 763 return isinstance(kind, Enum) 764 765 766def IsReferenceKind(kind): 767 return isinstance(kind, ReferenceKind) 768 769 770def IsNullableKind(kind): 771 return IsReferenceKind(kind) and kind.is_nullable 772 773 774def IsMapKind(kind): 775 return isinstance(kind, Map) 776 777 778def IsObjectKind(kind): 779 return IsPointerKind(kind) or IsUnionKind(kind) 780 781 782def IsPointerKind(kind): 783 return (IsStructKind(kind) or IsArrayKind(kind) or IsStringKind(kind) or 784 IsMapKind(kind)) 785 786 787# Please note that it doesn't include any interface kind. 788def IsAnyHandleKind(kind): 789 return (IsGenericHandleKind(kind) or 790 IsDataPipeConsumerKind(kind) or 791 IsDataPipeProducerKind(kind) or 792 IsMessagePipeKind(kind) or 793 IsSharedBufferKind(kind)) 794 795 796def IsAnyInterfaceKind(kind): 797 return (IsInterfaceKind(kind) or IsInterfaceRequestKind(kind) or 798 IsAssociatedKind(kind)) 799 800 801def IsAnyHandleOrInterfaceKind(kind): 802 return IsAnyHandleKind(kind) or IsAnyInterfaceKind(kind) 803 804 805def IsAssociatedKind(kind): 806 return (IsAssociatedInterfaceKind(kind) or 807 IsAssociatedInterfaceRequestKind(kind)) 808 809 810def HasCallbacks(interface): 811 for method in interface.methods: 812 if method.response_parameters != None: 813 return True 814 return False 815 816 817# Finds out whether an interface passes associated interfaces and associated 818# interface requests. 819def PassesAssociatedKinds(interface): 820 def _ContainsAssociatedKinds(kind, visited_kinds): 821 if kind in visited_kinds: 822 # No need to examine the kind again. 823 return False 824 visited_kinds.add(kind) 825 if IsAssociatedKind(kind): 826 return True 827 if IsArrayKind(kind): 828 return _ContainsAssociatedKinds(kind.kind, visited_kinds) 829 if IsStructKind(kind) or IsUnionKind(kind): 830 for field in kind.fields: 831 if _ContainsAssociatedKinds(field.kind, visited_kinds): 832 return True 833 if IsMapKind(kind): 834 # No need to examine the key kind, only primitive kinds and non-nullable 835 # string are allowed to be key kinds. 836 return _ContainsAssociatedKinds(kind.value_kind, visited_kinds) 837 return False 838 839 visited_kinds = set() 840 for method in interface.methods: 841 for param in method.parameters: 842 if _ContainsAssociatedKinds(param.kind, visited_kinds): 843 return True 844 if method.response_parameters != None: 845 for param in method.response_parameters: 846 if _ContainsAssociatedKinds(param.kind, visited_kinds): 847 return True 848 return False 849 850 851def HasSyncMethods(interface): 852 for method in interface.methods: 853 if method.sync: 854 return True 855 return False 856 857 858def ContainsHandlesOrInterfaces(kind): 859 """Check if the kind contains any handles. 860 861 This check is recursive so it checks all struct fields, containers elements, 862 etc. 863 864 Args: 865 struct: {Kind} The kind to check. 866 867 Returns: 868 {bool}: True if the kind contains handles. 869 """ 870 # We remember the types we already checked to avoid infinite recursion when 871 # checking recursive (or mutually recursive) types: 872 checked = set() 873 def Check(kind): 874 if kind.spec in checked: 875 return False 876 checked.add(kind.spec) 877 if IsStructKind(kind): 878 return any(Check(field.kind) for field in kind.fields) 879 elif IsUnionKind(kind): 880 return any(Check(field.kind) for field in kind.fields) 881 elif IsAnyHandleKind(kind): 882 return True 883 elif IsAnyInterfaceKind(kind): 884 return True 885 elif IsArrayKind(kind): 886 return Check(kind.kind) 887 elif IsMapKind(kind): 888 return Check(kind.key_kind) or Check(kind.value_kind) 889 else: 890 return False 891 return Check(kind) 892