| Index: third_party/mojo/src/mojo/public/python/mojo_bindings/interface_reflection.py
|
| diff --git a/third_party/mojo/src/mojo/public/python/mojo_bindings/reflection.py b/third_party/mojo/src/mojo/public/python/mojo_bindings/interface_reflection.py
|
| similarity index 59%
|
| copy from third_party/mojo/src/mojo/public/python/mojo_bindings/reflection.py
|
| copy to third_party/mojo/src/mojo/public/python/mojo_bindings/interface_reflection.py
|
| index e41601a6d0c8960e06e0049f94fbe0d28d7c2fe1..8ce3882106ba7deb30bd3b0b562365e5fc8bebdb 100644
|
| --- a/third_party/mojo/src/mojo/public/python/mojo_bindings/reflection.py
|
| +++ b/third_party/mojo/src/mojo/public/python/mojo_bindings/interface_reflection.py
|
| @@ -1,145 +1,26 @@
|
| -# Copyright 2014 The Chromium Authors. All rights reserved.
|
| +# Copyright 2015 The Chromium Authors. All rights reserved.
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| -"""The metaclasses used by the mojo python bindings."""
|
| +"""
|
| +The metaclasses used by the mojo python bindings for interfaces.
|
| +
|
| +It is splitted from mojo_bindings.reflection because it uses some generated code
|
| +that would create a cyclic dependency.
|
| +"""
|
|
|
| -import itertools
|
| import logging
|
| import sys
|
|
|
| # pylint: disable=F0401
|
| +import interface_control_messages_mojom
|
| import mojo_bindings.messaging as messaging
|
| import mojo_bindings.promise as promise
|
| +import mojo_bindings.reflection as reflection
|
| import mojo_bindings.serialization as serialization
|
| import mojo_system
|
|
|
|
|
| -class MojoEnumType(type):
|
| - """Meta class for enumerations.
|
| -
|
| - Usage:
|
| - class MyEnum(object):
|
| - __metaclass__ = MojoEnumType
|
| - VALUES = [
|
| - ('A', 0),
|
| - 'B',
|
| - ('C', 5),
|
| - ]
|
| -
|
| - This will define a enum with 3 values, 'A' = 0, 'B' = 1 and 'C' = 5.
|
| - """
|
| -
|
| - def __new__(mcs, name, bases, dictionary):
|
| - dictionary['__slots__'] = ()
|
| - dictionary['__new__'] = None
|
| - for value in dictionary.pop('VALUES', []):
|
| - if not isinstance(value, tuple):
|
| - raise ValueError('incorrect value: %r' % value)
|
| - key, enum_value = value
|
| - if isinstance(key, str) and isinstance(enum_value, int):
|
| - dictionary[key] = enum_value
|
| - else:
|
| - raise ValueError('incorrect value: %r' % value)
|
| - return type.__new__(mcs, name, bases, dictionary)
|
| -
|
| - def __setattr__(cls, key, value):
|
| - raise AttributeError('can\'t set attribute')
|
| -
|
| - def __delattr__(cls, key):
|
| - raise AttributeError('can\'t delete attribute')
|
| -
|
| -
|
| -class MojoStructType(type):
|
| - """Meta class for structs.
|
| -
|
| - Usage:
|
| - class MyStruct(object):
|
| - __metaclass__ = MojoStructType
|
| - DESCRIPTOR = {
|
| - 'constants': {
|
| - 'C1': 1,
|
| - 'C2': 2,
|
| - },
|
| - 'enums': {
|
| - 'ENUM1': [
|
| - ('V1', 1),
|
| - 'V2',
|
| - ],
|
| - 'ENUM2': [
|
| - ('V1', 1),
|
| - 'V2',
|
| - ],
|
| - },
|
| - 'fields': [
|
| - SingleFieldGroup('x', _descriptor.TYPE_INT32, 0, 0),
|
| - ],
|
| - }
|
| -
|
| - This will define an struct, with:
|
| - - 2 constants 'C1' and 'C2';
|
| - - 2 enums 'ENUM1' and 'ENUM2', each of those having 2 values, 'V1' and
|
| - 'V2';
|
| - - 1 int32 field named 'x'.
|
| - """
|
| -
|
| - def __new__(mcs, name, bases, dictionary):
|
| - dictionary['__slots__'] = ('_fields')
|
| - descriptor = dictionary.pop('DESCRIPTOR', {})
|
| -
|
| - # Add constants
|
| - dictionary.update(descriptor.get('constants', {}))
|
| -
|
| - # Add enums
|
| - enums = descriptor.get('enums', {})
|
| - for key in enums:
|
| - dictionary[key] = MojoEnumType(key, (object,), { 'VALUES': enums[key] })
|
| -
|
| - # Add fields
|
| - groups = descriptor.get('fields', [])
|
| -
|
| - fields = list(
|
| - itertools.chain.from_iterable([group.descriptors for group in groups]))
|
| - fields.sort(key=lambda f: f.index)
|
| - for field in fields:
|
| - dictionary[field.name] = _BuildProperty(field)
|
| -
|
| - # Add init
|
| - dictionary['__init__'] = _StructInit(fields)
|
| -
|
| - # Add serialization method
|
| - serialization_object = serialization.Serialization(groups)
|
| - def Serialize(self, handle_offset=0):
|
| - return serialization_object.Serialize(self, handle_offset)
|
| - dictionary['Serialize'] = Serialize
|
| -
|
| - # pylint: disable=W0212
|
| - def AsDict(self):
|
| - return self._fields
|
| - dictionary['AsDict'] = AsDict
|
| -
|
| - def Deserialize(cls, context):
|
| - result = cls.__new__(cls)
|
| - fields = {}
|
| - serialization_object.Deserialize(fields, context)
|
| - result._fields = fields
|
| - return result
|
| - dictionary['Deserialize'] = classmethod(Deserialize)
|
| -
|
| - dictionary['__eq__'] = _StructEq(fields)
|
| - dictionary['__ne__'] = _StructNe
|
| -
|
| - return type.__new__(mcs, name, bases, dictionary)
|
| -
|
| - # Prevent adding new attributes, or mutating constants.
|
| - def __setattr__(cls, key, value):
|
| - raise AttributeError('can\'t set attribute')
|
| -
|
| - # Prevent deleting constants.
|
| - def __delattr__(cls, key):
|
| - raise AttributeError('can\'t delete attribute')
|
| -
|
| -
|
| class MojoInterfaceType(type):
|
| """Meta class for interfaces.
|
|
|
| @@ -147,6 +28,8 @@ class MojoInterfaceType(type):
|
| class MyInterface(object):
|
| __metaclass__ = MojoInterfaceType
|
| DESCRIPTOR = {
|
| + 'fully_qualified_name': 'service::MyInterface'
|
| + 'version': 3,
|
| 'methods': [
|
| {
|
| 'name': 'FireAndForget',
|
| @@ -183,7 +66,8 @@ class MojoInterfaceType(type):
|
| dictionary[method.name] = _NotImplemented
|
| fully_qualified_name = descriptor['fully_qualified_name']
|
|
|
| - interface_manager = InterfaceManager(fully_qualified_name, methods)
|
| + interface_manager = InterfaceManager(
|
| + fully_qualified_name, descriptor['version'], methods)
|
| dictionary.update({
|
| 'manager': None,
|
| '_interface_manager': interface_manager,
|
| @@ -206,34 +90,6 @@ class MojoInterfaceType(type):
|
| raise AttributeError('can\'t delete attribute')
|
|
|
|
|
| -class InterfaceProxy(object):
|
| - """
|
| - A proxy allows to access a remote interface through a message pipe.
|
| - """
|
| - pass
|
| -
|
| -
|
| -class InterfaceRequest(object):
|
| - """
|
| - An interface request allows to send a request for an interface to a remote
|
| - object and start using it immediately.
|
| - """
|
| -
|
| - def __init__(self, handle):
|
| - self._handle = handle
|
| -
|
| - def IsPending(self):
|
| - return self._handle.IsValid()
|
| -
|
| - def PassMessagePipe(self):
|
| - result = self._handle
|
| - self._handle = None
|
| - return result
|
| -
|
| - def Bind(self, impl):
|
| - type(impl).manager.Bind(impl, self.PassMessagePipe())
|
| -
|
| -
|
| class InterfaceManager(object):
|
| """
|
| Manager for an interface class. The manager contains the operation that allows
|
| @@ -241,19 +97,20 @@ class InterfaceManager(object):
|
| over a pipe.
|
| """
|
|
|
| - def __init__(self, name, methods):
|
| + def __init__(self, name, version, methods):
|
| self.name = name
|
| + self.version = version
|
| self.methods = methods
|
| self.interface_class = None
|
| self._proxy_class = None
|
| self._stub_class = None
|
|
|
| - def Proxy(self, handle):
|
| + def Proxy(self, handle, version=0):
|
| router = messaging.Router(handle)
|
| error_handler = _ProxyErrorHandler()
|
| router.SetErrorHandler(error_handler)
|
| router.Start()
|
| - return self._InternalProxy(router, error_handler)
|
| + return self._InternalProxy(router, error_handler, version)
|
|
|
| # pylint: disable=W0212
|
| def Bind(self, impl, handle):
|
| @@ -270,15 +127,15 @@ class InterfaceManager(object):
|
|
|
| # Give an instance manager to the implementation to allow it to close
|
| # the connection.
|
| - impl.manager = InstanceManager(router, error_handler)
|
| + impl.manager = InstanceManager(self, router, error_handler)
|
|
|
| router.Start()
|
|
|
| def NewRequest(self):
|
| pipe = mojo_system.MessagePipe()
|
| - return (self.Proxy(pipe.handle0), InterfaceRequest(pipe.handle1))
|
| + return (self.Proxy(pipe.handle0), reflection.InterfaceRequest(pipe.handle1))
|
|
|
| - def _InternalProxy(self, router, error_handler):
|
| + def _InternalProxy(self, router, error_handler, version):
|
| if error_handler is None:
|
| error_handler = _ProxyErrorHandler()
|
|
|
| @@ -289,13 +146,15 @@ class InterfaceManager(object):
|
| }
|
| for method in self.methods:
|
| dictionary[method.name] = _ProxyMethodCall(method)
|
| - self._proxy_class = type('%sProxy' % self.name,
|
| - (self.interface_class, InterfaceProxy),
|
| - dictionary)
|
| + self._proxy_class = type(
|
| + '%sProxy' % self.name,
|
| + (self.interface_class, reflection.InterfaceProxy),
|
| + dictionary)
|
|
|
| proxy = self._proxy_class(router, error_handler)
|
| # Give an instance manager to the proxy to allow to close the connection.
|
| - proxy.manager = InstanceManager(router, error_handler)
|
| + proxy.manager = ProxyInstanceManager(
|
| + self, proxy, router, error_handler, version)
|
| return proxy
|
|
|
| def _Stub(self, impl):
|
| @@ -318,7 +177,8 @@ class InstanceManager(object):
|
| Manager for the implementation of an interface or a proxy. The manager allows
|
| to control the connection over the pipe.
|
| """
|
| - def __init__(self, router, error_handler):
|
| + def __init__(self, interface_manager, router, error_handler):
|
| + self.interface_manager = interface_manager
|
| self._router = router
|
| self._error_handler = error_handler
|
| assert self._error_handler is not None
|
| @@ -335,25 +195,79 @@ class InstanceManager(object):
|
| self._error_handler.AddCallback(lambda _: callback(), False)
|
|
|
|
|
| -class _MethodDescriptor(object):
|
| +class ProxyInstanceManager(InstanceManager):
|
| + """
|
| + Manager for the implementation of a proxy. The manager allows to control the
|
| + connection over the pipe.
|
| + """
|
| + def __init__(self, interface_manager, proxy, router, error_handler, version):
|
| + super(ProxyInstanceManager, self).__init__(
|
| + interface_manager, router, error_handler)
|
| + self.proxy = proxy
|
| + self.version = version
|
| + self._run_method = _ProxyMethodCall(_BaseMethodDescriptor(
|
| + 'Run',
|
| + interface_control_messages_mojom.RUN_MESSAGE_ID,
|
| + interface_control_messages_mojom.RunMessageParams,
|
| + interface_control_messages_mojom.RunResponseMessageParams))
|
| + self._run_or_close_pipe_method = _ProxyMethodCall(_BaseMethodDescriptor(
|
| + 'RunOrClosePipe',
|
| + interface_control_messages_mojom.RUN_OR_CLOSE_PIPE_MESSAGE_ID,
|
| + interface_control_messages_mojom.RunOrClosePipeMessageParams,
|
| + None))
|
| +
|
| + def QueryVersion(self):
|
| + params = interface_control_messages_mojom.RunMessageParams()
|
| + params.reserved0 = 16
|
| + params.reserved1 = 0
|
| + params.query_version = (
|
| + interface_control_messages_mojom.QueryVersion())
|
| + def ToVersion(r):
|
| + self.version = r.query_version_result.version
|
| + return self.version
|
| + return self._run_method(self.proxy, **params.AsDict()).Then(ToVersion)
|
| +
|
| + def RequireVersion(self, version):
|
| + if self.version >= version:
|
| + return
|
| + self.version = version
|
| + params = interface_control_messages_mojom.RunOrClosePipeMessageParams()
|
| + params.reserved0 = 16
|
| + params.reserved1 = 0
|
| + params.require_version = interface_control_messages_mojom.RequireVersion()
|
| + params.require_version.version = version
|
| + return self._run_or_close_pipe_method(self.proxy, **params.AsDict())
|
| +
|
| +
|
| +class _BaseMethodDescriptor(object):
|
| + def __init__(self, name, ordinal, parameters_struct, response_struct):
|
| + self.name = name
|
| + self.ordinal = ordinal
|
| + self.parameters_struct = parameters_struct
|
| + self.response_struct = response_struct
|
| +
|
| +
|
| +class _MethodDescriptor(_BaseMethodDescriptor):
|
| def __init__(self, descriptor):
|
| - self.name = descriptor['name']
|
| - self.ordinal = descriptor['ordinal']
|
| - self.parameters_struct = _ConstructParameterStruct(
|
| - descriptor['parameters'], self.name, "Parameters")
|
| - self.response_struct = _ConstructParameterStruct(
|
| - descriptor.get('responses'), self.name, "Responses")
|
| + name = descriptor['name']
|
| + super(_MethodDescriptor, self).__init__(
|
| + name,
|
| + descriptor['ordinal'],
|
| + _ConstructParameterStruct(
|
| + descriptor['parameters'], name, "Parameters"),
|
| + _ConstructParameterStruct(
|
| + descriptor.get('responses'), name, "Responses"))
|
|
|
|
|
| def _ConstructParameterStruct(descriptor, name, suffix):
|
| if descriptor is None:
|
| return None
|
| parameter_dictionary = {
|
| - '__metaclass__': MojoStructType,
|
| + '__metaclass__': reflection.MojoStructType,
|
| '__module__': __name__,
|
| 'DESCRIPTOR': descriptor,
|
| }
|
| - return MojoStructType(
|
| + return reflection.MojoStructType(
|
| '%s%s' % (name, suffix),
|
| (object,),
|
| parameter_dictionary)
|
| @@ -404,56 +318,6 @@ class _Retainer(object):
|
| _Retainer._RETAINED.remove(self)
|
|
|
|
|
| -def _StructInit(fields):
|
| - def _Init(self, *args, **kwargs):
|
| - if len(args) + len(kwargs) > len(fields):
|
| - raise TypeError('__init__() takes %d argument (%d given)' %
|
| - (len(fields), len(args) + len(kwargs)))
|
| - self._fields = {}
|
| - for f, a in zip(fields, args):
|
| - self.__setattr__(f.name, a)
|
| - remaining_fields = set(x.name for x in fields[len(args):])
|
| - for name in kwargs:
|
| - if not name in remaining_fields:
|
| - if name in (x.name for x in fields[:len(args)]):
|
| - raise TypeError(
|
| - '__init__() got multiple values for keyword argument %r' % name)
|
| - raise TypeError('__init__() got an unexpected keyword argument %r' %
|
| - name)
|
| - self.__setattr__(name, kwargs[name])
|
| - return _Init
|
| -
|
| -
|
| -def _BuildProperty(field):
|
| - """Build the property for the given field."""
|
| -
|
| - # pylint: disable=W0212
|
| - def Get(self):
|
| - if field.name not in self._fields:
|
| - self._fields[field.name] = field.GetDefaultValue()
|
| - return self._fields[field.name]
|
| -
|
| - # pylint: disable=W0212
|
| - def Set(self, value):
|
| - self._fields[field.name] = field.field_type.Convert(value)
|
| -
|
| - return property(Get, Set)
|
| -
|
| -
|
| -def _StructEq(fields):
|
| - def _Eq(self, other):
|
| - if type(self) is not type(other):
|
| - return False
|
| - for field in fields:
|
| - if getattr(self, field.name) != getattr(other, field.name):
|
| - return False
|
| - return True
|
| - return _Eq
|
| -
|
| -def _StructNe(self, other):
|
| - return not self.__eq__(other)
|
| -
|
| -
|
| def _ProxyInit(self, router, error_handler):
|
| self._router = router
|
| self._error_handler = error_handler
|
| @@ -466,7 +330,7 @@ def _ProxyMethodCall(method):
|
| flags = messaging.MESSAGE_EXPECTS_RESPONSE_FLAG
|
| def _Call(self, *args, **kwargs):
|
| def GenerationMethod(resolve, reject):
|
| - message = _GetMessage(method, flags, *args, **kwargs)
|
| + message = _GetMessage(method, flags, None, *args, **kwargs)
|
| if method.response_struct:
|
| def Accept(message):
|
| try:
|
| @@ -504,18 +368,23 @@ def _ProxyMethodCall(method):
|
| return _Call
|
|
|
|
|
| -def _GetMessage(method, flags, *args, **kwargs):
|
| - if flags == messaging.MESSAGE_IS_RESPONSE_FLAG:
|
| - struct = method.response_struct(*args, **kwargs)
|
| - else:
|
| - struct = method.parameters_struct(*args, **kwargs)
|
| - header = messaging.MessageHeader(method.ordinal, flags)
|
| +def _GetMessageWithStruct(struct, ordinal, flags, request_id):
|
| + header = messaging.MessageHeader(
|
| + ordinal, flags, 0 if request_id is None else request_id)
|
| data = header.Serialize()
|
| (payload, handles) = struct.Serialize()
|
| data.extend(payload)
|
| return messaging.Message(data, handles, header)
|
|
|
|
|
| +def _GetMessage(method, flags, request_id, *args, **kwargs):
|
| + if flags == messaging.MESSAGE_IS_RESPONSE_FLAG:
|
| + struct = method.response_struct(*args, **kwargs)
|
| + else:
|
| + struct = method.parameters_struct(*args, **kwargs)
|
| + return _GetMessageWithStruct(struct, method.ordinal, flags, request_id)
|
| +
|
| +
|
| def _StubInit(self, impl):
|
| self.impl = impl
|
|
|
| @@ -526,6 +395,11 @@ def _StubAccept(methods):
|
| try:
|
| header = message.header
|
| assert header.expects_response == bool(responder)
|
| + if header.message_type == interface_control_messages_mojom.RUN_MESSAGE_ID:
|
| + return _RunMessage(self.impl.manager, message, responder)
|
| + if (header.message_type ==
|
| + interface_control_messages_mojom.RUN_OR_CLOSE_PIPE_MESSAGE_ID):
|
| + return _RunMessageOrClosePipe(self.impl.manager, message)
|
| assert header.message_type in methods_by_ordinal
|
| method = methods_by_ordinal[header.message_type]
|
| payload = message.payload
|
| @@ -539,12 +413,13 @@ def _StubAccept(methods):
|
| if isinstance(response, dict):
|
| response_message = _GetMessage(method,
|
| messaging.MESSAGE_IS_RESPONSE_FLAG,
|
| + header.request_id,
|
| **response)
|
| else:
|
| response_message = _GetMessage(method,
|
| messaging.MESSAGE_IS_RESPONSE_FLAG,
|
| + header.request_id,
|
| response)
|
| - response_message.header.request_id = header.request_id
|
| return responder.Accept(response_message)
|
| p = SendResponse(response)
|
| if self.impl.manager:
|
| @@ -563,5 +438,29 @@ def _StubAccept(methods):
|
| return Accept
|
|
|
|
|
| +def _RunMessage(manager, message, responder):
|
| + response = interface_control_messages_mojom.RunResponseMessageParams()
|
| + response.reserved0 = 16
|
| + response.reserved1 = 0
|
| + response.query_version_result = (
|
| + interface_control_messages_mojom.QueryVersionResult())
|
| + response.query_version_result.version = manager.interface_manager.version
|
| + response_message = _GetMessageWithStruct(
|
| + response,
|
| + interface_control_messages_mojom.RUN_MESSAGE_ID,
|
| + messaging.MESSAGE_IS_RESPONSE_FLAG,
|
| + message.header.request_id)
|
| + return responder.Accept(response_message)
|
| +
|
| +
|
| +def _RunMessageOrClosePipe(manager, message):
|
| + payload = message.payload
|
| + query = (
|
| + interface_control_messages_mojom.RunOrClosePipeMessageParams.Deserialize(
|
| + serialization.RootDeserializationContext(payload.data,
|
| + payload.handles)))
|
| + return query.require_version.version <= manager.interface_manager.version
|
| +
|
| +
|
| def _NotImplemented(*_1, **_2):
|
| raise NotImplementedError()
|
|
|