• 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  """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