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() |