• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  ReferenceKind.AddSharedProperty('name')
298  ReferenceKind.AddSharedProperty('native_only')
299  ReferenceKind.AddSharedProperty('module')
300  ReferenceKind.AddSharedProperty('imported_from')
301  ReferenceKind.AddSharedProperty('fields')
302  ReferenceKind.AddSharedProperty('attributes')
303
304  def __init__(self, name=None, module=None, attributes=None):
305    if name is not None:
306      spec = 'x:' + name
307    else:
308      spec = None
309    ReferenceKind.__init__(self, spec)
310    self.name = name
311    self.native_only = False
312    self.module = module
313    self.imported_from = None
314    self.fields = []
315    self.attributes = attributes
316
317  def Repr(self, as_ref=True):
318    if as_ref:
319      return '<%s name=%r imported_from=%s>' % (
320          self.__class__.__name__, self.name,
321          Repr(self.imported_from, as_ref=True))
322    else:
323      return GenericRepr(self, {'name': False, 'fields': False,
324                                'imported_from': True})
325
326  def AddField(self, name, kind, ordinal=None, default=None, attributes=None):
327    field = StructField(name, kind, ordinal, default, attributes)
328    self.fields.append(field)
329    return field
330
331
332class Union(ReferenceKind):
333  """A union of several kinds.
334
335  Attributes:
336    name: {str} The name of the union type.
337    module: {Module} The defining module.
338    imported_from: {dict} Information about where this union was
339        imported from.
340    fields: {List[UnionField]} The members of the union.
341    attributes: {dict} Additional information about the union, such as
342        which Java class name to use to represent it in the generated
343        bindings.
344  """
345  ReferenceKind.AddSharedProperty('name')
346  ReferenceKind.AddSharedProperty('module')
347  ReferenceKind.AddSharedProperty('imported_from')
348  ReferenceKind.AddSharedProperty('fields')
349  ReferenceKind.AddSharedProperty('attributes')
350
351  def __init__(self, name=None, module=None, attributes=None):
352    if name is not None:
353      spec = 'x:' + name
354    else:
355      spec = None
356    ReferenceKind.__init__(self, spec)
357    self.name = name
358    self.module = module
359    self.imported_from = None
360    self.fields = []
361    self.attributes = attributes
362
363  def Repr(self, as_ref=True):
364    if as_ref:
365      return '<%s spec=%r is_nullable=%r fields=%s>' % (
366          self.__class__.__name__, self.spec, self.is_nullable,
367          Repr(self.fields))
368    else:
369      return GenericRepr(self, {'fields': True, 'is_nullable': False})
370
371  def AddField(self, name, kind, ordinal=None, attributes=None):
372    field = UnionField(name, kind, ordinal, None, attributes)
373    self.fields.append(field)
374    return field
375
376
377class Array(ReferenceKind):
378  """An array.
379
380  Attributes:
381    kind: {Kind} The type of the elements. May be None.
382    length: The number of elements. None if unknown.
383  """
384
385  ReferenceKind.AddSharedProperty('kind')
386  ReferenceKind.AddSharedProperty('length')
387
388  def __init__(self, kind=None, length=None):
389    if kind is not None:
390      if length is not None:
391        spec = 'a%d:%s' % (length, kind.spec)
392      else:
393        spec = 'a:%s' % kind.spec
394
395      ReferenceKind.__init__(self, spec)
396    else:
397      ReferenceKind.__init__(self)
398    self.kind = kind
399    self.length = length
400
401  def Repr(self, as_ref=True):
402    if as_ref:
403      return '<%s spec=%r is_nullable=%r kind=%s length=%r>' % (
404          self.__class__.__name__, self.spec, self.is_nullable, Repr(self.kind),
405          self.length)
406    else:
407      return GenericRepr(self, {'kind': True, 'length': False,
408                                'is_nullable': False})
409
410
411class Map(ReferenceKind):
412  """A map.
413
414  Attributes:
415    key_kind: {Kind} The type of the keys. May be None.
416    value_kind: {Kind} The type of the elements. May be None.
417  """
418  ReferenceKind.AddSharedProperty('key_kind')
419  ReferenceKind.AddSharedProperty('value_kind')
420
421  def __init__(self, key_kind=None, value_kind=None):
422    if (key_kind is not None and value_kind is not None):
423      ReferenceKind.__init__(self,
424                             'm[' + key_kind.spec + '][' + value_kind.spec +
425                             ']')
426      if IsNullableKind(key_kind):
427        raise Exception("Nullable kinds cannot be keys in maps.")
428      if IsStructKind(key_kind):
429        # TODO(erg): It would sometimes be nice if we could key on struct
430        # values. However, what happens if the struct has a handle in it? Or
431        # non-copyable data like an array?
432        raise Exception("Structs cannot be keys in maps.")
433      if IsAnyHandleKind(key_kind):
434        raise Exception("Handles cannot be keys in maps.")
435      if IsInterfaceKind(key_kind):
436        raise Exception("Interfaces cannot be keys in maps.")
437      if IsArrayKind(key_kind):
438        raise Exception("Arrays cannot be keys in maps.")
439    else:
440      ReferenceKind.__init__(self)
441
442    self.key_kind = key_kind
443    self.value_kind = value_kind
444
445  def Repr(self, as_ref=True):
446    if as_ref:
447      return '<%s spec=%r is_nullable=%r key_kind=%s value_kind=%s>' % (
448          self.__class__.__name__, self.spec, self.is_nullable,
449          Repr(self.key_kind), Repr(self.value_kind))
450    else:
451      return GenericRepr(self, {'key_kind': True, 'value_kind': True})
452
453
454class InterfaceRequest(ReferenceKind):
455  ReferenceKind.AddSharedProperty('kind')
456
457  def __init__(self, kind=None):
458    if kind is not None:
459      if not isinstance(kind, Interface):
460        raise Exception(
461            "Interface request requires %r to be an interface." % kind.spec)
462      ReferenceKind.__init__(self, 'r:' + kind.spec)
463    else:
464      ReferenceKind.__init__(self)
465    self.kind = kind
466
467
468class AssociatedInterfaceRequest(ReferenceKind):
469  ReferenceKind.AddSharedProperty('kind')
470
471  def __init__(self, kind=None):
472    if kind is not None:
473      if not isinstance(kind, InterfaceRequest):
474        raise Exception(
475            "Associated interface request requires %r to be an interface "
476            "request." % kind.spec)
477      assert not kind.is_nullable
478      ReferenceKind.__init__(self, 'asso:' + kind.spec)
479    else:
480      ReferenceKind.__init__(self)
481    self.kind = kind.kind if kind is not None else None
482
483
484class Parameter(object):
485  def __init__(self, name=None, kind=None, ordinal=None, default=None,
486               attributes=None):
487    self.name = name
488    self.ordinal = ordinal
489    self.kind = kind
490    self.default = default
491    self.attributes = attributes
492
493  def Repr(self, as_ref=True):
494    return '<%s name=%r kind=%s>' % (self.__class__.__name__, self.name,
495                                     self.kind.Repr(as_ref=True))
496
497  @property
498  def min_version(self):
499    return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
500        if self.attributes else None
501
502
503class Method(object):
504  def __init__(self, interface, name, ordinal=None, attributes=None):
505    self.interface = interface
506    self.name = name
507    self.ordinal = ordinal
508    self.parameters = []
509    self.response_parameters = None
510    self.attributes = attributes
511
512  def Repr(self, as_ref=True):
513    if as_ref:
514      return '<%s name=%r>' % (self.__class__.__name__, self.name)
515    else:
516      return GenericRepr(self, {'name': False, 'parameters': True,
517                                'response_parameters': True})
518
519  def AddParameter(self, name, kind, ordinal=None, default=None,
520                   attributes=None):
521    parameter = Parameter(name, kind, ordinal, default, attributes)
522    self.parameters.append(parameter)
523    return parameter
524
525  def AddResponseParameter(self, name, kind, ordinal=None, default=None,
526                           attributes=None):
527    if self.response_parameters == None:
528      self.response_parameters = []
529    parameter = Parameter(name, kind, ordinal, default, attributes)
530    self.response_parameters.append(parameter)
531    return parameter
532
533  @property
534  def min_version(self):
535    return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
536        if self.attributes else None
537
538  @property
539  def sync(self):
540    return self.attributes.get(ATTRIBUTE_SYNC) \
541        if self.attributes else None
542
543
544class Interface(ReferenceKind):
545  ReferenceKind.AddSharedProperty('module')
546  ReferenceKind.AddSharedProperty('name')
547  ReferenceKind.AddSharedProperty('imported_from')
548  ReferenceKind.AddSharedProperty('methods')
549  ReferenceKind.AddSharedProperty('attributes')
550
551  def __init__(self, name=None, module=None, attributes=None):
552    if name is not None:
553      spec = 'x:' + name
554    else:
555      spec = None
556    ReferenceKind.__init__(self, spec)
557    self.module = module
558    self.name = name
559    self.imported_from = None
560    self.methods = []
561    self.attributes = attributes
562
563  def Repr(self, as_ref=True):
564    if as_ref:
565      return '<%s name=%r>' % (self.__class__.__name__, self.name)
566    else:
567      return GenericRepr(self, {'name': False, 'attributes': False,
568                                'methods': False})
569
570  def AddMethod(self, name, ordinal=None, attributes=None):
571    method = Method(self, name, ordinal, attributes)
572    self.methods.append(method)
573    return method
574
575  # TODO(451323): Remove when the language backends no longer rely on this.
576  @property
577  def client(self):
578    return None
579
580
581class AssociatedInterface(ReferenceKind):
582  ReferenceKind.AddSharedProperty('kind')
583
584  def __init__(self, kind=None):
585    if kind is not None:
586      if not isinstance(kind, Interface):
587        raise Exception(
588            "Associated interface requires %r to be an interface." % kind.spec)
589      assert not kind.is_nullable
590      ReferenceKind.__init__(self, 'asso:' + kind.spec)
591    else:
592      ReferenceKind.__init__(self)
593    self.kind = kind
594
595
596class EnumField(object):
597  def __init__(self, name=None, value=None, attributes=None,
598               numeric_value=None):
599    self.name = name
600    self.value = value
601    self.attributes = attributes
602    self.numeric_value = numeric_value
603
604  @property
605  def min_version(self):
606    return self.attributes.get(ATTRIBUTE_MIN_VERSION) \
607        if self.attributes else None
608
609
610class Enum(Kind):
611  def __init__(self, name=None, module=None, attributes=None):
612    self.module = module
613    self.name = name
614    self.native_only = False
615    self.imported_from = None
616    if name is not None:
617      spec = 'x:' + name
618    else:
619      spec = None
620    Kind.__init__(self, spec)
621    self.fields = []
622    self.attributes = attributes
623
624  def Repr(self, as_ref=True):
625    if as_ref:
626      return '<%s name=%r>' % (self.__class__.__name__, self.name)
627    else:
628      return GenericRepr(self, {'name': False, 'fields': False})
629
630  @property
631  def extensible(self):
632    return self.attributes.get(ATTRIBUTE_EXTENSIBLE, False) \
633        if self.attributes else False
634
635
636class Module(object):
637  def __init__(self, name=None, namespace=None, attributes=None):
638    self.name = name
639    self.path = name
640    self.namespace = namespace
641    self.structs = []
642    self.unions = []
643    self.interfaces = []
644    self.kinds = {}
645    self.attributes = attributes
646
647  def __repr__(self):
648    # Gives us a decent __repr__ for modules.
649    return self.Repr()
650
651  def Repr(self, as_ref=True):
652    if as_ref:
653      return '<%s name=%r namespace=%r>' % (
654          self.__class__.__name__, self.name, self.namespace)
655    else:
656      return GenericRepr(self, {'name': False, 'namespace': False,
657                                'attributes': False, 'structs': False,
658                                'interfaces': False, 'unions': False})
659
660  def AddInterface(self, name, attributes=None):
661    interface = Interface(name, self, attributes)
662    self.interfaces.append(interface)
663    return interface
664
665  def AddStruct(self, name, attributes=None):
666    struct = Struct(name, self, attributes)
667    self.structs.append(struct)
668    return struct
669
670  def AddUnion(self, name, attributes=None):
671    union = Union(name, self, attributes)
672    self.unions.append(union)
673    return union
674
675
676def IsBoolKind(kind):
677  return kind.spec == BOOL.spec
678
679
680def IsFloatKind(kind):
681  return kind.spec == FLOAT.spec
682
683
684def IsIntegralKind(kind):
685  return (kind.spec == BOOL.spec or
686          kind.spec == INT8.spec or
687          kind.spec == INT16.spec or
688          kind.spec == INT32.spec or
689          kind.spec == INT64.spec or
690          kind.spec == UINT8.spec or
691          kind.spec == UINT16.spec or
692          kind.spec == UINT32.spec or
693          kind.spec == UINT64.spec)
694
695
696def IsStringKind(kind):
697  return kind.spec == STRING.spec or kind.spec == NULLABLE_STRING.spec
698
699
700def IsGenericHandleKind(kind):
701  return kind.spec == HANDLE.spec or kind.spec == NULLABLE_HANDLE.spec
702
703
704def IsDataPipeConsumerKind(kind):
705  return kind.spec == DCPIPE.spec or kind.spec == NULLABLE_DCPIPE.spec
706
707
708def IsDataPipeProducerKind(kind):
709  return kind.spec == DPPIPE.spec or kind.spec == NULLABLE_DPPIPE.spec
710
711
712def IsMessagePipeKind(kind):
713  return kind.spec == MSGPIPE.spec or kind.spec == NULLABLE_MSGPIPE.spec
714
715
716def IsSharedBufferKind(kind):
717  return (kind.spec == SHAREDBUFFER.spec or
718          kind.spec == NULLABLE_SHAREDBUFFER.spec)
719
720
721def IsStructKind(kind):
722  return isinstance(kind, Struct)
723
724
725def IsUnionKind(kind):
726  return isinstance(kind, Union)
727
728
729def IsArrayKind(kind):
730  return isinstance(kind, Array)
731
732
733def IsInterfaceKind(kind):
734  return isinstance(kind, Interface)
735
736
737def IsAssociatedInterfaceKind(kind):
738  return isinstance(kind, AssociatedInterface)
739
740
741def IsInterfaceRequestKind(kind):
742  return isinstance(kind, InterfaceRequest)
743
744
745def IsAssociatedInterfaceRequestKind(kind):
746  return isinstance(kind, AssociatedInterfaceRequest)
747
748
749def IsEnumKind(kind):
750  return isinstance(kind, Enum)
751
752
753def IsReferenceKind(kind):
754  return isinstance(kind, ReferenceKind)
755
756
757def IsNullableKind(kind):
758  return IsReferenceKind(kind) and kind.is_nullable
759
760
761def IsMapKind(kind):
762  return isinstance(kind, Map)
763
764
765def IsObjectKind(kind):
766  return IsPointerKind(kind) or IsUnionKind(kind)
767
768
769def IsPointerKind(kind):
770  return (IsStructKind(kind) or IsArrayKind(kind) or IsStringKind(kind) or
771          IsMapKind(kind))
772
773
774# Please note that interface is not considered as handle kind, since it is an
775# aggregate type consisting of a handle and a version number.
776def IsAnyHandleKind(kind):
777  return (IsGenericHandleKind(kind) or
778          IsDataPipeConsumerKind(kind) or
779          IsDataPipeProducerKind(kind) or
780          IsMessagePipeKind(kind) or
781          IsSharedBufferKind(kind) or
782          IsInterfaceRequestKind(kind))
783
784
785def IsAnyHandleOrInterfaceKind(kind):
786  return (IsAnyHandleKind(kind) or IsInterfaceKind(kind) or
787          IsAssociatedKind(kind))
788
789
790def IsAssociatedKind(kind):
791  return (IsAssociatedInterfaceKind(kind) or
792          IsAssociatedInterfaceRequestKind(kind))
793
794
795def HasCallbacks(interface):
796  for method in interface.methods:
797    if method.response_parameters != None:
798      return True
799  return False
800
801
802# Finds out whether an interface passes associated interfaces and associated
803# interface requests.
804def PassesAssociatedKinds(interface):
805  def _ContainsAssociatedKinds(kind, visited_kinds):
806    if kind in visited_kinds:
807      # No need to examine the kind again.
808      return False
809    visited_kinds.add(kind)
810    if IsAssociatedKind(kind):
811      return True
812    if IsArrayKind(kind):
813      return _ContainsAssociatedKinds(kind.kind, visited_kinds)
814    if IsStructKind(kind) or IsUnionKind(kind):
815      for field in kind.fields:
816        if _ContainsAssociatedKinds(field.kind, visited_kinds):
817          return True
818    if IsMapKind(kind):
819      # No need to examine the key kind, only primitive kinds and non-nullable
820      # string are allowed to be key kinds.
821      return _ContainsAssociatedKinds(kind.value_kind, visited_kinds)
822    return False
823
824  visited_kinds = set()
825  for method in interface.methods:
826    for param in method.parameters:
827      if _ContainsAssociatedKinds(param.kind, visited_kinds):
828        return True
829    if method.response_parameters != None:
830      for param in method.response_parameters:
831        if _ContainsAssociatedKinds(param.kind, visited_kinds):
832          return True
833  return False
834
835
836def HasSyncMethods(interface):
837  for method in interface.methods:
838    if method.sync:
839      return True
840  return False
841