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
16class Kind(object):
17  def __init__(self, spec=None):
18    self.spec = spec
19    self.parent_kind = None
20
21
22class ReferenceKind(Kind):
23  """ReferenceKind represents pointer types and handle types.
24     A type is nullable means that NULL (for pointer types) or invalid handle
25     (for handle 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.
80BOOL                  = Kind('b')
81INT8                  = Kind('i8')
82INT16                 = Kind('i16')
83INT32                 = Kind('i32')
84INT64                 = Kind('i64')
85UINT8                 = Kind('u8')
86UINT16                = Kind('u16')
87UINT32                = Kind('u32')
88UINT64                = Kind('u64')
89FLOAT                 = Kind('f')
90DOUBLE                = Kind('d')
91STRING                = ReferenceKind('s')
92HANDLE                = ReferenceKind('h')
93DCPIPE                = ReferenceKind('h:d:c')
94DPPIPE                = ReferenceKind('h:d:p')
95MSGPIPE               = ReferenceKind('h:m')
96SHAREDBUFFER          = ReferenceKind('h:s')
97NULLABLE_STRING       = ReferenceKind('?s', True)
98NULLABLE_HANDLE       = ReferenceKind('?h', True)
99NULLABLE_DCPIPE       = ReferenceKind('?h:d:c', True)
100NULLABLE_DPPIPE       = ReferenceKind('?h:d:p', True)
101NULLABLE_MSGPIPE      = ReferenceKind('?h:m', True)
102NULLABLE_SHAREDBUFFER = ReferenceKind('?h:s', True)
103
104
105# Collection of all Primitive types
106PRIMITIVES = (
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
133class NamedValue(object):
134  def __init__(self, module, parent_kind, name):
135    self.module = module
136    self.namespace = module.namespace
137    self.parent_kind = parent_kind
138    self.name = name
139    self.imported_from = None
140
141  def GetSpec(self):
142    return (self.namespace + '.' +
143        (self.parent_kind and (self.parent_kind.name + '.') or "") +
144        self.name)
145
146
147class BuiltinValue(object):
148  def __init__(self, value):
149    self.value = value
150
151
152class ConstantValue(NamedValue):
153  def __init__(self, module, parent_kind, constant):
154    NamedValue.__init__(self, module, parent_kind, constant.name)
155    self.constant = constant
156
157
158class EnumValue(NamedValue):
159  def __init__(self, module, enum, field):
160    NamedValue.__init__(self, module, enum.parent_kind, field.name)
161    self.enum = enum
162
163  def GetSpec(self):
164    return (self.namespace + '.' +
165        (self.parent_kind and (self.parent_kind.name + '.') or "") +
166        self.enum.name + '.' + self.name)
167
168
169class Constant(object):
170  def __init__(self, name=None, kind=None, value=None):
171    self.name = name
172    self.kind = kind
173    self.value = value
174
175
176class Field(object):
177  def __init__(self, name=None, kind=None, ordinal=None, default=None):
178    self.name = name
179    self.kind = kind
180    self.ordinal = ordinal
181    self.default = default
182
183
184class Struct(ReferenceKind):
185  ReferenceKind.AddSharedProperty('name')
186  ReferenceKind.AddSharedProperty('module')
187  ReferenceKind.AddSharedProperty('imported_from')
188  ReferenceKind.AddSharedProperty('fields')
189
190  def __init__(self, name=None, module=None):
191    if name is not None:
192      spec = 'x:' + name
193    else:
194      spec = None
195    ReferenceKind.__init__(self, spec)
196    self.name = name
197    self.module = module
198    self.imported_from = None
199    self.fields = []
200
201  def AddField(self, name, kind, ordinal=None, default=None):
202    field = Field(name, kind, ordinal, default)
203    self.fields.append(field)
204    return field
205
206
207class Array(ReferenceKind):
208  ReferenceKind.AddSharedProperty('kind')
209
210  def __init__(self, kind=None):
211    if kind is not None:
212      ReferenceKind.__init__(self, 'a:' + kind.spec)
213    else:
214      ReferenceKind.__init__(self)
215    self.kind = kind
216
217
218class FixedArray(ReferenceKind):
219  ReferenceKind.AddSharedProperty('kind')
220  ReferenceKind.AddSharedProperty('length')
221
222  def __init__(self, length=-1, kind=None):
223    if kind is not None:
224      ReferenceKind.__init__(self, 'a%d:%s' % (length, kind.spec))
225    else:
226      ReferenceKind.__init__(self)
227    self.kind = kind
228    self.length = length
229
230
231class InterfaceRequest(ReferenceKind):
232  ReferenceKind.AddSharedProperty('kind')
233
234  def __init__(self, kind=None):
235    if kind is not None:
236      ReferenceKind.__init__(self, 'r:' + kind.spec)
237    else:
238      ReferenceKind.__init__(self)
239    self.kind = kind
240
241
242class Parameter(object):
243  def __init__(self, name=None, kind=None, ordinal=None, default=None):
244    self.name = name
245    self.ordinal = ordinal
246    self.kind = kind
247    self.default = default
248
249
250class Method(object):
251  def __init__(self, interface, name, ordinal=None):
252    self.interface = interface
253    self.name = name
254    self.ordinal = ordinal
255    self.parameters = []
256    self.response_parameters = None
257
258  def AddParameter(self, name, kind, ordinal=None, default=None):
259    parameter = Parameter(name, kind, ordinal, default)
260    self.parameters.append(parameter)
261    return parameter
262
263  def AddResponseParameter(self, name, kind, ordinal=None, default=None):
264    if self.response_parameters == None:
265      self.response_parameters = []
266    parameter = Parameter(name, kind, ordinal, default)
267    self.response_parameters.append(parameter)
268    return parameter
269
270
271class Interface(ReferenceKind):
272  ReferenceKind.AddSharedProperty('module')
273  ReferenceKind.AddSharedProperty('name')
274  ReferenceKind.AddSharedProperty('imported_from')
275  ReferenceKind.AddSharedProperty('client')
276  ReferenceKind.AddSharedProperty('methods')
277
278  def __init__(self, name=None, client=None, module=None):
279    if name is not None:
280      spec = 'x:' + name
281    else:
282      spec = None
283    ReferenceKind.__init__(self, spec)
284    self.module = module
285    self.name = name
286    self.imported_from = None
287    self.client = client
288    self.methods = []
289
290  def AddMethod(self, name, ordinal=None):
291    method = Method(self, name, ordinal=ordinal)
292    self.methods.append(method)
293    return method
294
295
296class EnumField(object):
297  def __init__(self, name=None, value=None):
298    self.name = name
299    self.value = value
300
301
302class Enum(Kind):
303  def __init__(self, name=None, module=None):
304    self.module = module
305    self.name = name
306    self.imported_from = None
307    if name is not None:
308      spec = 'x:' + name
309    else:
310      spec = None
311    Kind.__init__(self, spec)
312    self.fields = []
313
314
315class Module(object):
316  def __init__(self, name=None, namespace=None):
317    self.name = name
318    self.path = name
319    self.namespace = namespace
320    self.structs = []
321    self.interfaces = []
322
323  def AddInterface(self, name):
324    self.interfaces.append(Interface(name, module=self))
325    return interface
326
327  def AddStruct(self, name):
328    struct=Struct(name, module=self)
329    self.structs.append(struct)
330    return struct
331
332
333def IsBoolKind(kind):
334  return kind.spec == BOOL.spec
335
336
337def IsFloatKind(kind):
338  return kind.spec == FLOAT.spec
339
340
341def IsStringKind(kind):
342  return kind.spec == STRING.spec or kind.spec == NULLABLE_STRING.spec
343
344
345def IsHandleKind(kind):
346  return kind.spec == HANDLE.spec or kind.spec == NULLABLE_HANDLE.spec
347
348
349def IsDataPipeConsumerKind(kind):
350  return kind.spec == DCPIPE.spec or kind.spec == NULLABLE_DCPIPE.spec
351
352
353def IsDataPipeProducerKind(kind):
354  return kind.spec == DPPIPE.spec or kind.spec == NULLABLE_DPPIPE.spec
355
356
357def IsMessagePipeKind(kind):
358  return kind.spec == MSGPIPE.spec or kind.spec == NULLABLE_MSGPIPE.spec
359
360
361def IsSharedBufferKind(kind):
362  return (kind.spec == SHAREDBUFFER.spec or
363          kind.spec == NULLABLE_SHAREDBUFFER.spec)
364
365
366def IsStructKind(kind):
367  return isinstance(kind, Struct)
368
369
370def IsArrayKind(kind):
371  return isinstance(kind, Array)
372
373
374def IsFixedArrayKind(kind):
375  return isinstance(kind, FixedArray)
376
377
378def IsInterfaceKind(kind):
379  return isinstance(kind, Interface)
380
381
382def IsInterfaceRequestKind(kind):
383  return isinstance(kind, InterfaceRequest)
384
385
386def IsEnumKind(kind):
387  return isinstance(kind, Enum)
388
389
390def IsReferenceKind(kind):
391  return isinstance(kind, ReferenceKind)
392
393
394def IsNullableKind(kind):
395  return IsReferenceKind(kind) and kind.is_nullable
396
397
398def IsAnyArrayKind(kind):
399  return IsArrayKind(kind) or IsFixedArrayKind(kind)
400
401
402def IsObjectKind(kind):
403  return IsStructKind(kind) or IsAnyArrayKind(kind) or IsStringKind(kind)
404
405
406def IsNonInterfaceHandleKind(kind):
407  return (IsHandleKind(kind) or
408          IsDataPipeConsumerKind(kind) or
409          IsDataPipeProducerKind(kind) or
410          IsMessagePipeKind(kind) or
411          IsSharedBufferKind(kind))
412
413
414def IsAnyHandleKind(kind):
415  return (IsNonInterfaceHandleKind(kind) or
416          IsInterfaceKind(kind) or
417          IsInterfaceRequestKind(kind))
418
419
420def IsMoveOnlyKind(kind):
421  return IsObjectKind(kind) or IsAnyHandleKind(kind)
422
423
424def HasCallbacks(interface):
425  for method in interface.methods:
426    if method.response_parameters != None:
427      return True
428  return False
429
430