diff options
author | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-09 22:35:51 +0000 |
---|---|---|
committer | darin@chromium.org <darin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-09 22:35:51 +0000 |
commit | 5e1a832c8186ef29546b6b60f90d7974ca72d3c9 (patch) | |
tree | 41b3fd3eaf316e7353a566c2b8923566788dd446 /mojo/public | |
parent | 92028f1406eeb252247b55b8db63b1b8cdf69945 (diff) | |
download | chromium_src-5e1a832c8186ef29546b6b60f90d7974ca72d3c9.zip chromium_src-5e1a832c8186ef29546b6b60f90d7974ca72d3c9.tar.gz chromium_src-5e1a832c8186ef29546b6b60f90d7974ca72d3c9.tar.bz2 |
Mojo: Replace RemotePtr with InterfacePtr and InterfaceImpl
Interfaces no longer have explicit Peer attributes. An interface may now optionally have a Client interface, in which case a SetClient method will be auto-generated.
InterfacePtr is a proxy to a remote instance of an interface. InterfaceImpl is a base class used when implementing an interface. Both have facilities for binding to a pipe, etc. An InterfacePtr is movable but not copyable and looks a lot like RemotePtr save for how it gets initialized (via the Bind method now).
I've added some new top-level functions:
MakeProxy - makes it easy to initialize an InterfacePtr in say a member initializer list.
BindToPipe - this is how you bind an InterfaceImpl to a pipe. once bound, they cannot be unbound until the object is destroyed or the pipe is closed.
BindToProxy - builds on top of BindToPipe, however, it hides the details of the pipe. What you get back is an InterfacePtr.
Generated C++ code now passes InterfacePtr instead of InterfaceHandle. As a result, we have far less need for typed subclasses of MessagePipeHandle, so I eliminated them. The code that needs to deal with raw handles generally has to deal with {Scoped}MessagePipeHandle, and adding strong typing to these handles doesn't seem helpful anymore.
R=davemoore@chromium.org
Review URL: https://codereview.chromium.org/265793015
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269443 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo/public')
40 files changed, 801 insertions, 543 deletions
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn index 66b8733..9753c73 100644 --- a/mojo/public/cpp/bindings/BUILD.gn +++ b/mojo/public/cpp/bindings/BUILD.gn @@ -9,10 +9,10 @@ source_set("bindings") { "buffer.h", "callback.h", "error_handler.h", - "interface.h", + "interface_ptr.h", "message.h", + "no_interface.h", "passable.h", - "remote_ptr.h", "sync_dispatcher.h", "type_converter.h", "lib/array.cc", @@ -27,13 +27,13 @@ source_set("bindings") { "lib/connector.h", "lib/fixed_buffer.cc", "lib/fixed_buffer.h", - "lib/interface.cc", "lib/message.cc", "lib/message_builder.cc", "lib/message_builder.h", "lib/message_internal.h", "lib/message_queue.cc", "lib/message_queue.h", + "lib/no_interface.cc", "lib/router.cc", "lib/router.h", "lib/scratch_buffer.cc", diff --git a/mojo/public/cpp/bindings/error_handler.h b/mojo/public/cpp/bindings/error_handler.h index 25c0d65..a6f0a4a 100644 --- a/mojo/public/cpp/bindings/error_handler.h +++ b/mojo/public/cpp/bindings/error_handler.h @@ -7,10 +7,20 @@ namespace mojo { +// This interface is used to report connection errors. class ErrorHandler { public: virtual ~ErrorHandler() {} - virtual void OnError() = 0; + virtual void OnConnectionError() = 0; +}; + +// Used when you'd like to extend a base class with the same method signature +// as ErrorHandler. +template <typename Base> +class WithErrorHandler : public Base { + public: + virtual ~WithErrorHandler() {} + virtual void OnConnectionError() = 0; }; } // namespace mojo diff --git a/mojo/public/cpp/bindings/interface.h b/mojo/public/cpp/bindings/interface.h deleted file mode 100644 index bba8fef..0000000 --- a/mojo/public/cpp/bindings/interface.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2014 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. - -#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_H_ - -#include <assert.h> - -#include "mojo/public/cpp/bindings/message.h" -#include "mojo/public/cpp/system/core.h" - -namespace mojo { - - -// NoInterface is for use in cases when a non-existent or empty interface is -// needed (e.g., when the Mojom "Peer" attribute is not present). - -class NoInterface; - -class NoInterfaceStub : public MessageReceiver { - public: - NoInterfaceStub(NoInterface* unused) {} - virtual bool Accept(Message* message) MOJO_OVERRIDE; - virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) - MOJO_OVERRIDE; -}; - -class NoInterface { - public: - typedef NoInterfaceStub _Stub; - typedef NoInterface _Peer; -}; - - -// AnyInterface is for use in cases where any interface would do (e.g., see the -// Shell::Connect method). - -typedef NoInterface AnyInterface; - - -// InterfaceHandle<S> - -template <typename S> -class InterfaceHandle : public MessagePipeHandle { - public: - InterfaceHandle() {} - explicit InterfaceHandle(MojoHandle value) : MessagePipeHandle(value) {} -}; - - -// Interface<S> - -template <typename S> -struct Interface { - typedef InterfaceHandle<S> Handle; - typedef ScopedHandleBase<InterfaceHandle<S> > ScopedHandle; -}; - -template <> -struct Interface<mojo::NoInterface> { - typedef MessagePipeHandle Handle; - typedef ScopedMessagePipeHandle ScopedHandle; -}; - - -// InterfacePipe<S,P> is used to construct a MessagePipe with typed interfaces -// on either end. - -template <typename S, typename P = typename S::_Peer> -class InterfacePipe { - public: - InterfacePipe() { - typename Interface<S>::Handle h0; - typename Interface<P>::Handle h1; - MojoResult result MOJO_ALLOW_UNUSED = - MojoCreateMessagePipe(h0.mutable_value(), h1.mutable_value()); - assert(result == MOJO_RESULT_OK); - handle_to_self.reset(h0); - handle_to_peer.reset(h1); - } - - typename Interface<S>::ScopedHandle handle_to_self; - typename Interface<P>::ScopedHandle handle_to_peer; -}; - -// TODO(darin): Once we have the ability to use C++11 features, consider -// defining a template alias for ScopedInterfaceHandle<S>. - -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_H_ diff --git a/mojo/public/cpp/bindings/interface_impl.h b/mojo/public/cpp/bindings/interface_impl.h new file mode 100644 index 0000000..ec6bc91 --- /dev/null +++ b/mojo/public/cpp/bindings/interface_impl.h @@ -0,0 +1,79 @@ +// Copyright 2014 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_IMPL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_IMPL_H_ + +#include "mojo/public/cpp/bindings/lib/interface_impl_internal.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { + +// InterfaceImpl<..> is designed to be the base class of an interface +// implementation. It may be bound to a pipe or a proxy, see BindToPipe and +// BindToProxy. +// +// NOTE: A base class of WithErrorHandler<Interface> is used to avoid multiple +// inheritance. This base class inserts the signature of ErrorHandler into the +// inheritance chain. +template <typename Interface> +class InterfaceImpl : public WithErrorHandler<Interface> { + public: + InterfaceImpl() : internal_state_(this) {} + virtual ~InterfaceImpl() {} + + // Subclasses must handle connection errors. + virtual void OnConnectionError() = 0; + + // DO NOT USE. Exposed only for internal use and for testing. + internal::InterfaceImplState<Interface>* internal_state() { + return &internal_state_; + } + + private: + internal::InterfaceImplState<Interface> internal_state_; + MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceImpl); +}; + +// Takes an instance of an InterfaceImpl<..> subclass and binds it to the given +// MessagePipe. The instance is returned for convenience in member initializer +// lists, etc. If the pipe is closed, the instance's OnConnectionError method +// will be called. +// +// The instance is also bound to the current thread. Its methods will only be +// called on the current thread, and if the current thread exits, then it will +// also be deleted, and along with it, its end point of the pipe will be closed. +// +// Before returning, the instance will receive a SetClient call, providing it +// with a proxy to the client on the other end of the pipe. +template <typename Impl> +Impl* BindToPipe(Impl* instance, + ScopedMessagePipeHandle handle, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + instance->internal_state()->Bind(handle.Pass(), waiter); + return instance; +} + +// Takes an instance of an InterfaceImpl<..> subclass and binds it to the given +// InterfacePtr<..>. The instance is returned for convenience in member +// initializer lists, etc. If the pipe is closed, the instance's +// OnConnectionError method will be called. +// +// The instance is also bound to the current thread. Its methods will only be +// called on the current thread, and if the current thread exits, then it will +// also be deleted, and along with it, its end point of the pipe will be closed. +// +// Before returning, the instance will receive a SetClient call, providing it +// with a proxy to the client on the other end of the pipe. +template <typename Impl, typename Interface> +Impl* BindToProxy(Impl* instance, + InterfacePtr<Interface>* ptr, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + instance->internal_state()->BindProxy(ptr, waiter); + return instance; +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_IMPL_H_ diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h new file mode 100644 index 0000000..91bd6ba --- /dev/null +++ b/mojo/public/cpp/bindings/interface_ptr.h @@ -0,0 +1,116 @@ +// Copyright 2014 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_ + +#include <assert.h> + +#include <algorithm> + +#include "mojo/public/cpp/bindings/error_handler.h" +#include "mojo/public/cpp/bindings/lib/interface_ptr_internal.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +class ErrorHandler; + +// InterfacePtr represents a proxy to a remote instance of an interface. +template <typename Interface> +class InterfacePtr { + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InterfacePtr, RValue) + public: + InterfacePtr() {} + + InterfacePtr(RValue other) { + other.object->internal_state_.Swap(&internal_state_); + } + InterfacePtr& operator=(RValue other) { + other.object->internal_state_.Swap(&internal_state_); + return *this; + } + + ~InterfacePtr() {} + + Interface* get() const { + return internal_state_.instance(); + } + Interface* operator->() const { return get(); } + Interface* operator*() const { return get(); } + + void reset() { + State doomed; + internal_state_.Swap(&doomed); + } + + // This method configures the InterfacePtr<..> to be a proxy to a remote + // object on the other end of the given pipe. + // + // The proxy is bound to the current thread, which means its methods may + // only be called on the current thread. + // + // To move a bound InterfacePtr<..> to another thread, call + // ResetAndReturnMessagePipe. Then create a new InterfacePtr<..> on another + // thread, and bind the new InterfacePtr<..> to the message pipe on that + // thread. + void Bind(ScopedMessagePipeHandle handle, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + reset(); + internal_state_.ConfigureProxy(handle.Pass(), waiter); + } + + // This method may be called to query if the underlying pipe has encountered + // an error. If true, this means method calls made on this interface will be + // dropped (and may have already been dropped) on the floor. + bool encountered_error() const { + assert(internal_state_.router()); + return internal_state_.router()->encountered_error(); + } + + // This method may be called to register an ErrorHandler to observe a + // connection error on the underlying pipe. The callback runs asynchronously + // from the current message loop. + void set_error_handler(ErrorHandler* error_handler) { + assert(internal_state_.router()); + internal_state_.router()->set_error_handler(error_handler); + } + + // Returns the underlying message pipe handle (if any) and resets the + // InterfacePtr<..> to its uninitialized state. This method is helpful if you + // need to move a proxy to another thread. See related notes for Bind. + ScopedMessagePipeHandle ResetAndReturnMessagePipe() { + State state; + internal_state_.Swap(&state); + return state.router() ? + state.router()->ReleaseMessagePipe() : ScopedMessagePipeHandle(); + } + + // DO NOT USE. Exposed only for internal use and for testing. + internal::InterfacePtrState<Interface>* internal_state() { + return &internal_state_; + } + + private: + typedef internal::InterfacePtrState<Interface> State; + State internal_state_; +}; + +// Takes a handle to the proxy end-point of a pipe. On the other end is +// presumed to be an interface implementation of type |Interface|. Returns a +// generated proxy to that interface, which may be used on the current thread. +// It is valid to call SetClient on the returned Interface to set an instance +// of Interface::Client. +template <typename Interface> +InterfacePtr<Interface> MakeProxy( + ScopedMessagePipeHandle handle, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + InterfacePtr<Interface> ptr; + if (handle.is_valid()) + ptr.Bind(handle.Pass(), waiter); + return ptr.Pass(); +} + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_ diff --git a/mojo/public/cpp/bindings/lib/array_internal.h b/mojo/public/cpp/bindings/lib/array_internal.h index 4ecad35..865bf1c 100644 --- a/mojo/public/cpp/bindings/lib/array_internal.h +++ b/mojo/public/cpp/bindings/lib/array_internal.h @@ -8,7 +8,6 @@ #include <new> #include "mojo/public/cpp/bindings/buffer.h" -#include "mojo/public/cpp/bindings/interface.h" #include "mojo/public/cpp/bindings/lib/bindings_internal.h" #include "mojo/public/cpp/bindings/lib/bindings_serialization.h" #include "mojo/public/cpp/bindings/passable.h" diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc index aa6c45e..d9ce9d1 100644 --- a/mojo/public/cpp/bindings/lib/connector.cc +++ b/mojo/public/cpp/bindings/lib/connector.cc @@ -38,7 +38,17 @@ void Connector::CloseMessagePipe() { Close(message_pipe_.Pass()); } +ScopedMessagePipeHandle Connector::ReleaseMessagePipe() { + if (async_wait_id_) { + waiter_->CancelWait(waiter_, async_wait_id_); + async_wait_id_ = 0; + } + return message_pipe_.Pass(); +} + bool Connector::Accept(Message* message) { + assert(message_pipe_.is_valid()); + if (error_) return false; @@ -99,7 +109,7 @@ void Connector::OnHandleReady(MojoResult result) { } if (error_ && error_handler_) - error_handler_->OnError(); + error_handler_->OnConnectionError(); } void Connector::WaitToReadMore() { diff --git a/mojo/public/cpp/bindings/lib/connector.h b/mojo/public/cpp/bindings/lib/connector.h index f32a170..6e9c1b9 100644 --- a/mojo/public/cpp/bindings/lib/connector.h +++ b/mojo/public/cpp/bindings/lib/connector.h @@ -53,9 +53,14 @@ class Connector : public MessageReceiver { // waiting to read from the pipe. bool encountered_error() const { return error_; } - // Closes the pipe, triggering the error state. + // Closes the pipe, triggering the error state. Connector is put into a + // quiescent state. void CloseMessagePipe(); + // Releases the pipe, not triggering the error state. Connector is put into + // a quiescent state. + ScopedMessagePipeHandle ReleaseMessagePipe(); + // MessageReceiver implementation: virtual bool Accept(Message* message) MOJO_OVERRIDE; virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) diff --git a/mojo/public/cpp/bindings/lib/interface_impl_internal.h b/mojo/public/cpp/bindings/lib/interface_impl_internal.h new file mode 100644 index 0000000..50fe566 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/interface_impl_internal.h @@ -0,0 +1,72 @@ +// Copyright 2014 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_ + +#include "mojo/public/cpp/bindings/error_handler.h" +#include "mojo/public/cpp/bindings/interface_ptr.h" +#include "mojo/public/cpp/system/macros.h" + +namespace mojo { +namespace internal { + +template <typename Interface> +class InterfaceImplState : public ErrorHandler { + public: + explicit InterfaceImplState(WithErrorHandler<Interface>* instance) + : router_(NULL), + proxy_(NULL) { + assert(instance); + stub_.set_sink(instance); + } + + virtual ~InterfaceImplState() { + delete proxy_; + if (router_) { + router_->set_error_handler(NULL); + delete router_; + } + } + + void BindProxy( + InterfacePtr<Interface>* ptr, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + MessagePipe pipe; + ptr->Bind(pipe.handle0.Pass(), waiter); + Bind(pipe.handle1.Pass(), waiter); + } + + void Bind(ScopedMessagePipeHandle handle, + MojoAsyncWaiter* waiter) { + assert(!router_); + + router_ = new Router(handle.Pass(), waiter); + router_->set_incoming_receiver(&stub_); + router_->set_error_handler(this); + + proxy_ = new typename Interface::Client_::Proxy_(router_); + + stub_.sink()->SetClient(proxy_); + } + + Router* router() { return router_; } + + private: + virtual void OnConnectionError() MOJO_OVERRIDE { + static_cast<WithErrorHandler<Interface>*>(stub_.sink())-> + OnConnectionError(); + } + + internal::Router* router_; + typename Interface::Client_::Proxy_* proxy_; + typename Interface::Stub_ stub_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(InterfaceImplState); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_IMPL_INTERNAL_H_ diff --git a/mojo/public/cpp/bindings/lib/interface_ptr_internal.h b/mojo/public/cpp/bindings/lib/interface_ptr_internal.h new file mode 100644 index 0000000..041a31c --- /dev/null +++ b/mojo/public/cpp/bindings/lib/interface_ptr_internal.h @@ -0,0 +1,108 @@ +// Copyright 2014 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_ + +#include <stdio.h> + +#include "mojo/public/cpp/bindings/lib/router.h" + +namespace mojo { +namespace internal { + +template <typename Interface> +class InterfacePtrState { + public: + InterfacePtrState() : instance_(NULL), client_(NULL), router_(NULL) {} + + ~InterfacePtrState() { + // Destruction order matters here. We delete |instance_| first, even though + // |router_| may have a reference to it, so that |~Interface| may have a + // shot at generating new outbound messages (ie, invoking client methods). + delete instance_; + delete router_; + delete client_; + } + + Interface* instance() const { return instance_; } + void set_instance(Interface* instance) { instance_ = instance; } + + Router* router() const { return router_; } + + bool is_configured_as_proxy() const { + // This question only makes sense if we have a bound pipe. + return router_ && !client_; + } + + void Swap(InterfacePtrState* other) { + std::swap(other->instance_, instance_); + std::swap(other->client_, client_); + std::swap(other->router_, router_); + } + + void ConfigureProxy(ScopedMessagePipeHandle handle, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + assert(!instance_); + assert(!router_); + + router_ = new Router(handle.Pass(), waiter); + ProxyWithStub* proxy = new ProxyWithStub(router_); + router_->set_incoming_receiver(&proxy->stub); + + instance_ = proxy; + } + + void ConfigureStub(ScopedMessagePipeHandle handle, + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { + assert(instance_); // Should have already been set! + assert(!router_); + + // Stub for binding to state_.instance + // Proxy for communicating to the client on the other end of the pipe. + + router_ = new Router(handle.Pass(), waiter); + ClientProxyWithStub* proxy = new ClientProxyWithStub(router_); + proxy->stub.set_sink(instance_); + router_->set_incoming_receiver(&proxy->stub); + + instance_->SetClient(proxy); + client_ = proxy; + } + + private: + class ProxyWithStub : public Interface::Proxy_ { + public: + explicit ProxyWithStub(MessageReceiver* receiver) + : Interface::Proxy_(receiver) { + } + virtual void SetClient(typename Interface::Client_* client) MOJO_OVERRIDE { + stub.set_sink(client); + } + typename Interface::Client_::Stub_ stub; + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(ProxyWithStub); + }; + + class ClientProxyWithStub : public Interface::Client_::Proxy_ { + public: + explicit ClientProxyWithStub(MessageReceiver* receiver) + : Interface::Client_::Proxy_(receiver) { + } + typename Interface::Stub_ stub; + private: + MOJO_DISALLOW_COPY_AND_ASSIGN(ClientProxyWithStub); + }; + + Interface* instance_; + typename Interface::Client_* client_; + Router* router_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(InterfacePtrState); +}; + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_INTERFACE_PTR_INTERNAL_H_ diff --git a/mojo/public/cpp/bindings/lib/interface.cc b/mojo/public/cpp/bindings/lib/no_interface.cc index 3b552be..7ce223a 100644 --- a/mojo/public/cpp/bindings/lib/interface.cc +++ b/mojo/public/cpp/bindings/lib/no_interface.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "mojo/public/cpp/bindings/interface.h" +#include "mojo/public/cpp/bindings/no_interface.h" namespace mojo { diff --git a/mojo/public/cpp/bindings/lib/router.h b/mojo/public/cpp/bindings/lib/router.h index 08c184e..220af7d 100644 --- a/mojo/public/cpp/bindings/lib/router.h +++ b/mojo/public/cpp/bindings/lib/router.h @@ -43,6 +43,14 @@ class Router : public MessageReceiver { // waiting to read from the pipe. bool encountered_error() const { return connector_.encountered_error(); } + void CloseMessagePipe() { + connector_.CloseMessagePipe(); + } + + ScopedMessagePipeHandle ReleaseMessagePipe() { + return connector_.ReleaseMessagePipe(); + } + // MessageReceiver implementation: virtual bool Accept(Message* message) MOJO_OVERRIDE; virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) diff --git a/mojo/public/cpp/bindings/no_interface.h b/mojo/public/cpp/bindings/no_interface.h new file mode 100644 index 0000000..02682d4 --- /dev/null +++ b/mojo/public/cpp/bindings/no_interface.h @@ -0,0 +1,52 @@ +// Copyright 2014 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_ + +#include <assert.h> + +#include "mojo/public/cpp/bindings/message.h" +#include "mojo/public/cpp/system/core.h" + +namespace mojo { + +// NoInterface is for use in cases when a non-existent or empty interface is +// needed (e.g., when the Mojom "Peer" attribute is not present). + +class NoInterfaceProxy; +class NoInterfaceStub; + +class NoInterface { + public: + typedef NoInterfaceProxy Proxy_; + typedef NoInterfaceStub Stub_; + typedef NoInterface Client_; + virtual ~NoInterface() {} + virtual void SetClient(NoInterface* client) {} +}; + +class NoInterfaceProxy : public NoInterface { + public: + explicit NoInterfaceProxy(MessageReceiver* receiver) {} +}; + +class NoInterfaceStub : public MessageReceiver { + public: + NoInterfaceStub() {} + void set_sink(NoInterface* sink) {} + virtual bool Accept(Message* message) MOJO_OVERRIDE; + virtual bool AcceptWithResponder(Message* message, MessageReceiver* responder) + MOJO_OVERRIDE; +}; + + +// AnyInterface is for use in cases where any interface would do (e.g., see the +// Shell::Connect method). + +typedef NoInterface AnyInterface; + +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_NO_INTERFACE_H_ diff --git a/mojo/public/cpp/bindings/remote_ptr.h b/mojo/public/cpp/bindings/remote_ptr.h deleted file mode 100644 index e1b9a5b..0000000 --- a/mojo/public/cpp/bindings/remote_ptr.h +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2013 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. - -#ifndef MOJO_PUBLIC_CPP_BINDINGS_REMOTE_PTR_H_ -#define MOJO_PUBLIC_CPP_BINDINGS_REMOTE_PTR_H_ - -#include <assert.h> - -#include "mojo/public/cpp/bindings/interface.h" -#include "mojo/public/cpp/bindings/lib/router.h" -#include "mojo/public/cpp/system/macros.h" - -namespace mojo { - -// A RemotePtr is a smart-pointer for managing the connection of a message pipe -// to an interface proxy. -// -// EXAMPLE: -// -// Given foo.mojom containing the following interfaces: -// -// [Peer=FooClient] -// interface Foo { -// void Ping(); -// }; -// -// [Peer=Foo] -// interface FooClient { -// void Pong(); -// }; -// -// On the client side of a service, RemotePtr might be used like so: -// -// class FooClientImpl : public FooClient { -// public: -// explicit FooClientImpl(ScopedFooHandle handle) -// : foo_(handle.Pass(), this) { -// foo_.Ping(); -// } -// virtual void Pong() { -// ... -// } -// private: -// mojo::RemotePtr<Foo> foo_; -// }; -// -// On the implementation side of a service, RemotePtr might be used like so: -// -// class FooImpl : public Foo { -// public: -// explicit FooImpl(ScopedFooClientHandle handle) -// : client_(handle.Pass(), this) { -// } -// virtual void Ping() { -// client_->Pong(); -// } -// private: -// mojo::RemotePtr<FooClient> client_; -// }; -// -// NOTE: -// -// 1- It is valid to pass NULL for the peer if you are not interested in -// receiving incoming messages. Those messages will still be consumed. -// -// 2- You may optionally register an ErrorHandler on the RemotePtr to be -// notified if the peer has gone away. Alternatively, you may poll the -// |encountered_error()| method to check if the peer has gone away. -// -template <typename S> -class RemotePtr { - struct State; - MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(RemotePtr, RValue) - - public: - RemotePtr() : state_(NULL) {} - explicit RemotePtr(typename Interface<S>::ScopedHandle interface_handle, - typename S::_Peer* peer, - ErrorHandler* error_handler = NULL, - MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) - : state_(new State(ScopedMessagePipeHandle(interface_handle.Pass()), peer, - error_handler, waiter)) { - } - - // Move-only constructor and operator=. - RemotePtr(RValue other) : state_(other.object->release()) {} - RemotePtr& operator=(RValue other) { - delete state_; - state_ = other.object->release(); - return *this; - } - - ~RemotePtr() { - delete state_; - } - - bool is_null() const { - return !state_; - } - - S* get() { - assert(state_); - return &state_->proxy; - } - - S* operator->() { - return get(); - } - - void reset() { - delete state_; - state_ = NULL; - } - - void reset(typename Interface<S>::ScopedHandle interface_handle, - typename S::_Peer* peer, - ErrorHandler* error_handler = NULL, - MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) { - delete state_; - state_ = new State(ScopedMessagePipeHandle(interface_handle.Pass()), peer, - error_handler, waiter); - } - - bool encountered_error() const { - assert(state_); - return state_->router.encountered_error(); - } - - internal::Router* router_for_testing() { - return &state_->router; - } - - private: - struct State { - State(ScopedMessagePipeHandle message_pipe, typename S::_Peer* peer, - ErrorHandler* error_handler, MojoAsyncWaiter* waiter) - : router(message_pipe.Pass(), waiter), - proxy(&router), - stub(peer) { - router.set_error_handler(error_handler); - if (peer) - router.set_incoming_receiver(&stub); - } - internal::Router router; - typename S::_Proxy proxy; - typename S::_Peer::_Stub stub; - }; - - State* release() { - State* state = state_; - state_ = NULL; - return state; - } - - State* state_; -}; - -} // namespace mojo - -#endif // MOJO_PUBLIC_CPP_BINDINGS_REMOTE_PTR_H_ diff --git a/mojo/public/cpp/bindings/sync_dispatcher.h b/mojo/public/cpp/bindings/sync_dispatcher.h index e267a17..7521180 100644 --- a/mojo/public/cpp/bindings/sync_dispatcher.h +++ b/mojo/public/cpp/bindings/sync_dispatcher.h @@ -16,11 +16,11 @@ class MessageReceiver; bool WaitForMessageAndDispatch(MessagePipeHandle handle, mojo::MessageReceiver* receiver); -template<typename S> class SyncDispatcher { +template<typename Interface> class SyncDispatcher { public: - SyncDispatcher(ScopedMessagePipeHandle message_pipe, S* sink) - : message_pipe_(message_pipe.Pass()), - stub_(sink) { + SyncDispatcher(ScopedMessagePipeHandle message_pipe, Interface* sink) + : message_pipe_(message_pipe.Pass()) { + stub_.set_sink(sink); } bool WaitAndDispatchOneMessage() { @@ -29,7 +29,7 @@ template<typename S> class SyncDispatcher { private: ScopedMessagePipeHandle message_pipe_; - typename S::_Stub stub_; + typename Interface::Stub_ stub_; }; } // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/array_unittest.cc b/mojo/public/cpp/bindings/tests/array_unittest.cc index dccd716..4bef4cd 100644 --- a/mojo/public/cpp/bindings/tests/array_unittest.cc +++ b/mojo/public/cpp/bindings/tests/array_unittest.cc @@ -4,7 +4,6 @@ #include "mojo/public/cpp/bindings/allocation_scope.h" #include "mojo/public/cpp/bindings/array.h" -#include "mojo/public/cpp/bindings/interface.h" #include "mojo/public/cpp/bindings/lib/fixed_buffer.h" #include "mojo/public/cpp/bindings/lib/scratch_buffer.h" #include "mojo/public/cpp/environment/environment.h" @@ -141,31 +140,6 @@ TEST(ArrayTest, MessagePipeHandlesAreClosed) { EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe1_value)); } -// Tests that Array<InterfaceHandle<S>> supports closing handles. -TEST(ArrayTest, InterfaceHandlesAreClosed) { - Environment env; - - InterfacePipe<sample::Port, sample::Port> pipe; - - MojoHandle pipe0_value = pipe.handle_to_self.get().value(); - MojoHandle pipe1_value = pipe.handle_to_peer.get().value(); - - { - AllocationScope scope; - - Array<sample::PortHandle>::Builder handles_builder(2); - handles_builder[0] = pipe.handle_to_self.Pass(); - handles_builder[1].reset(pipe.handle_to_peer.release()); - - MOJO_ALLOW_UNUSED Array<sample::PortHandle> handles = - handles_builder.Finish(); - } - - // We expect the pipes to have been closed. - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe0_value)); - EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(pipe1_value)); -} - } // namespace } // namespace test } // namespace mojo diff --git a/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc index 7df6db6..2cbd789 100644 --- a/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc +++ b/mojo/public/cpp/bindings/tests/handle_passing_unittest.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "mojo/public/cpp/bindings/allocation_scope.h" -#include "mojo/public/cpp/bindings/remote_ptr.h" #include "mojo/public/cpp/environment/environment.h" #include "mojo/public/cpp/test_support/test_utils.h" #include "mojo/public/cpp/utility/run_loop.h" @@ -17,10 +16,14 @@ namespace { const char kText1[] = "hello"; const char kText2[] = "world"; -class SampleFactoryImpl : public sample::Factory { +class SampleFactoryImpl : public InterfaceImpl<sample::Factory> { public: - explicit SampleFactoryImpl(sample::ScopedFactoryClientHandle handle) - : client_(handle.Pass(), this) { + virtual void OnConnectionError() MOJO_OVERRIDE { + delete this; + } + + virtual void SetClient(sample::FactoryClient* client) MOJO_OVERRIDE { + client_ = client; } virtual void DoStuff(const sample::Request& request, @@ -70,69 +73,17 @@ class SampleFactoryImpl : public sample::Factory { } private: - RemotePtr<sample::FactoryClient> client_; + sample::FactoryClient* client_; ScopedMessagePipeHandle pipe1_; }; class SampleFactoryClientImpl : public sample::FactoryClient { public: - explicit SampleFactoryClientImpl(sample::ScopedFactoryHandle handle) - : factory_(handle.Pass(), this), - got_response_(false) { - } - - void Start() { - expected_text_reply_ = kText1; - - ScopedMessagePipeHandle pipe0; - CreateMessagePipe(&pipe0, &pipe1_); - - EXPECT_TRUE(WriteTextMessage(pipe1_.get(), kText1)); - - ScopedMessagePipeHandle pipe2; - CreateMessagePipe(&pipe2, &pipe3_); - - EXPECT_TRUE(WriteTextMessage(pipe3_.get(), kText2)); - - AllocationScope scope; - sample::Request::Builder request; - request.set_x(1); - request.set_pipe(pipe2.Pass()); - factory_->DoStuff(request.Finish(), pipe0.Pass()); - } - - void StartNoPipes() { - expected_text_reply_.clear(); - - AllocationScope scope; - sample::Request::Builder request; - request.set_x(1); - factory_->DoStuff(request.Finish(), ScopedMessagePipeHandle().Pass()); + SampleFactoryClientImpl() : got_response_(false) { } - // Writes a string to a data pipe and passes the data pipe (consumer) to the - // factory. - void StartDataPipe() { - expected_text_reply_.clear(); - - ScopedDataPipeProducerHandle producer_handle; - ScopedDataPipeConsumerHandle consumer_handle; - MojoCreateDataPipeOptions options = { - sizeof(MojoCreateDataPipeOptions), - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, - 1, - 1024}; - ASSERT_EQ(MOJO_RESULT_OK, - CreateDataPipe(&options, &producer_handle, &consumer_handle)); - expected_text_reply_ = "got it"; - // +1 for \0. - uint32_t data_size = static_cast<uint32_t>(expected_text_reply_.size() + 1); - ASSERT_EQ(MOJO_RESULT_OK, - WriteDataRaw(producer_handle.get(), expected_text_reply_.c_str(), - &data_size, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)); - - AllocationScope scope; - factory_->DoStuff2(consumer_handle.Pass()); + void set_expected_text_reply(const std::string& expected_text_reply) { + expected_text_reply_ = expected_text_reply; } bool got_response() const { @@ -167,7 +118,6 @@ class SampleFactoryClientImpl : public sample::FactoryClient { } private: - RemotePtr<sample::Factory> factory_; ScopedMessagePipeHandle pipe1_; ScopedMessagePipeHandle pipe3_; std::string expected_text_reply_; @@ -176,6 +126,10 @@ class SampleFactoryClientImpl : public sample::FactoryClient { class HandlePassingTest : public testing::Test { public: + virtual void TearDown() { + PumpMessages(); + } + void PumpMessages() { loop_.RunUntilIdle(); } @@ -186,12 +140,31 @@ class HandlePassingTest : public testing::Test { }; TEST_F(HandlePassingTest, Basic) { - InterfacePipe<sample::Factory> pipe; + sample::FactoryPtr factory; + BindToProxy(new SampleFactoryImpl(), &factory); + + SampleFactoryClientImpl factory_client; + factory_client.set_expected_text_reply(kText1); + + factory->SetClient(&factory_client); + + ScopedMessagePipeHandle pipe0, pipe1; + CreateMessagePipe(&pipe0, &pipe1); + + EXPECT_TRUE(WriteTextMessage(pipe1.get(), kText1)); + + ScopedMessagePipeHandle pipe2, pipe3; + CreateMessagePipe(&pipe2, &pipe3); - SampleFactoryImpl factory(pipe.handle_to_peer.Pass()); - SampleFactoryClientImpl factory_client(pipe.handle_to_self.Pass()); + EXPECT_TRUE(WriteTextMessage(pipe3.get(), kText2)); - factory_client.Start(); + { + AllocationScope scope; + sample::Request::Builder request; + request.set_x(1); + request.set_pipe(pipe2.Pass()); + factory->DoStuff(request.Finish(), pipe0.Pass()); + } EXPECT_FALSE(factory_client.got_response()); @@ -201,12 +174,18 @@ TEST_F(HandlePassingTest, Basic) { } TEST_F(HandlePassingTest, PassInvalid) { - InterfacePipe<sample::Factory> pipe; + sample::FactoryPtr factory; + BindToProxy(new SampleFactoryImpl(), &factory); - SampleFactoryImpl factory(pipe.handle_to_peer.Pass()); - SampleFactoryClientImpl factory_client(pipe.handle_to_self.Pass()); + SampleFactoryClientImpl factory_client; + factory->SetClient(&factory_client); - factory_client.StartNoPipes(); + { + AllocationScope scope; + sample::Request::Builder request; + request.set_x(1); + factory->DoStuff(request.Finish(), ScopedMessagePipeHandle().Pass()); + } EXPECT_FALSE(factory_client.got_response()); @@ -217,12 +196,35 @@ TEST_F(HandlePassingTest, PassInvalid) { // Verifies DataPipeConsumer can be passed and read from. TEST_F(HandlePassingTest, DataPipe) { - InterfacePipe<sample::Factory> pipe; + sample::FactoryPtr factory; + BindToProxy(new SampleFactoryImpl(), &factory); + + SampleFactoryClientImpl factory_client; + factory->SetClient(&factory_client); - SampleFactoryImpl factory(pipe.handle_to_peer.Pass()); - SampleFactoryClientImpl factory_client(pipe.handle_to_self.Pass()); + // Writes a string to a data pipe and passes the data pipe (consumer) to the + // factory. + ScopedDataPipeProducerHandle producer_handle; + ScopedDataPipeConsumerHandle consumer_handle; + MojoCreateDataPipeOptions options = { + sizeof(MojoCreateDataPipeOptions), + MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, + 1, + 1024}; + ASSERT_EQ(MOJO_RESULT_OK, + CreateDataPipe(&options, &producer_handle, &consumer_handle)); + std::string expected_text_reply = "got it"; + factory_client.set_expected_text_reply(expected_text_reply); + // +1 for \0. + uint32_t data_size = static_cast<uint32_t>(expected_text_reply.size() + 1); + ASSERT_EQ(MOJO_RESULT_OK, + WriteDataRaw(producer_handle.get(), expected_text_reply.c_str(), + &data_size, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)); - ASSERT_NO_FATAL_FAILURE(factory_client.StartDataPipe()); + { + AllocationScope scope; + factory->DoStuff2(consumer_handle.Pass()); + } EXPECT_FALSE(factory_client.got_response()); @@ -232,8 +234,11 @@ TEST_F(HandlePassingTest, DataPipe) { } TEST_F(HandlePassingTest, PipesAreClosed) { - InterfacePipe<sample::Factory> pipe; - RemotePtr<sample::Factory> factory(pipe.handle_to_self.Pass(), NULL); + sample::FactoryPtr factory; + BindToProxy(new SampleFactoryImpl(), &factory); + + SampleFactoryClientImpl factory_client; + factory->SetClient(&factory_client); MessagePipe extra_pipe; diff --git a/mojo/public/cpp/bindings/tests/remote_ptr_unittest.cc b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc index 13311d4..3f9a80d 100644 --- a/mojo/public/cpp/bindings/tests/remote_ptr_unittest.cc +++ b/mojo/public/cpp/bindings/tests/interface_ptr_unittest.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "mojo/public/cpp/bindings/error_handler.h" -#include "mojo/public/cpp/bindings/remote_ptr.h" #include "mojo/public/cpp/environment/environment.h" #include "mojo/public/cpp/utility/run_loop.h" #include "mojo/public/interfaces/bindings/tests/math_calculator.mojom.h" @@ -21,7 +20,7 @@ class ErrorObserver : public ErrorHandler { bool encountered_error() const { return encountered_error_; } - virtual void OnError() MOJO_OVERRIDE { + virtual void OnConnectionError() MOJO_OVERRIDE { encountered_error_ = true; } @@ -29,13 +28,19 @@ class ErrorObserver : public ErrorHandler { bool encountered_error_; }; -class MathCalculatorImpl : public math::Calculator { +class MathCalculatorImpl : public InterfaceImpl<math::Calculator> { public: virtual ~MathCalculatorImpl() {} - explicit MathCalculatorImpl(math::ScopedCalculatorUIHandle ui_handle) - : ui_(ui_handle.Pass(), this), - total_(0.0) { + MathCalculatorImpl() : total_(0.0) { + } + + virtual void OnConnectionError() MOJO_OVERRIDE { + delete this; + } + + virtual void SetClient(math::CalculatorUI* ui) MOJO_OVERRIDE { + ui_ = ui; } virtual void Clear() MOJO_OVERRIDE { @@ -53,16 +58,16 @@ class MathCalculatorImpl : public math::Calculator { } private: - RemotePtr<math::CalculatorUI> ui_; + math::CalculatorUI* ui_; double total_; }; class MathCalculatorUIImpl : public math::CalculatorUI { public: - explicit MathCalculatorUIImpl(math::ScopedCalculatorHandle calculator_handle, - ErrorHandler* error_handler = NULL) - : calculator_(calculator_handle.Pass(), this, error_handler), + explicit MathCalculatorUIImpl(math::CalculatorPtr calculator) + : calculator_(calculator.Pass()), output_(0.0) { + calculator_->SetClient(this); } bool encountered_error() const { @@ -95,30 +100,31 @@ class MathCalculatorUIImpl : public math::CalculatorUI { output_ = value; } - RemotePtr<math::Calculator> calculator_; + math::CalculatorPtr calculator_; double output_; }; -class RemotePtrTest : public testing::Test { +class InterfacePtrTest : public testing::Test { public: - void PumpMessages() { + virtual ~InterfacePtrTest() { loop_.RunUntilIdle(); } - protected: - InterfacePipe<math::CalculatorUI> pipe_; + void PumpMessages() { + loop_.RunUntilIdle(); + } private: Environment env_; RunLoop loop_; }; -TEST_F(RemotePtrTest, EndToEnd) { - // Suppose this is instantiated in a process that has pipe0_. - MathCalculatorImpl calculator(pipe_.handle_to_self.Pass()); +TEST_F(InterfacePtrTest, EndToEnd) { + math::CalculatorPtr calc; + BindToProxy(new MathCalculatorImpl(), &calc); // Suppose this is instantiated in a process that has pipe1_. - MathCalculatorUIImpl calculator_ui(pipe_.handle_to_peer.Pass()); + MathCalculatorUIImpl calculator_ui(calc.Pass()); calculator_ui.Add(2.0); calculator_ui.Multiply(5.0); @@ -128,43 +134,48 @@ TEST_F(RemotePtrTest, EndToEnd) { EXPECT_EQ(10.0, calculator_ui.GetOutput()); } -TEST_F(RemotePtrTest, Movable) { - RemotePtr<math::Calculator> a; - RemotePtr<math::Calculator> b(pipe_.handle_to_peer.Pass(), NULL); +TEST_F(InterfacePtrTest, Movable) { + math::CalculatorPtr a; + math::CalculatorPtr b; + BindToProxy(new MathCalculatorImpl(), &b); - EXPECT_TRUE(a.is_null()); - EXPECT_FALSE(b.is_null()); + EXPECT_TRUE(!a.get()); + EXPECT_FALSE(!b.get()); a = b.Pass(); - EXPECT_FALSE(a.is_null()); - EXPECT_TRUE(b.is_null()); + EXPECT_FALSE(!a.get()); + EXPECT_TRUE(!b.get()); } -TEST_F(RemotePtrTest, Resettable) { - RemotePtr<math::Calculator> a; +TEST_F(InterfacePtrTest, Resettable) { + math::CalculatorPtr a; - EXPECT_TRUE(a.is_null()); + EXPECT_TRUE(!a.get()); - math::CalculatorHandle handle = pipe_.handle_to_peer.get(); + MessagePipe pipe; - a.reset(pipe_.handle_to_peer.Pass(), NULL); + // Save this so we can test it later. + Handle handle = pipe.handle0.get(); - EXPECT_FALSE(a.is_null()); + a = MakeProxy<math::Calculator>(pipe.handle0.Pass()); + + EXPECT_FALSE(!a.get()); a.reset(); - EXPECT_TRUE(a.is_null()); + EXPECT_TRUE(!a.get()); + EXPECT_FALSE(a.internal_state()->router()); // Test that handle was closed. EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, CloseRaw(handle)); } -TEST_F(RemotePtrTest, EncounteredError) { - MathCalculatorImpl* calculator = - new MathCalculatorImpl(pipe_.handle_to_self.Pass()); +TEST_F(InterfacePtrTest, EncounteredError) { + math::CalculatorPtr proxy; + MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy); - MathCalculatorUIImpl calculator_ui(pipe_.handle_to_peer.Pass()); + MathCalculatorUIImpl calculator_ui(proxy.Pass()); calculator_ui.Add(2.0); PumpMessages(); @@ -174,8 +185,8 @@ TEST_F(RemotePtrTest, EncounteredError) { calculator_ui.Multiply(5.0); EXPECT_FALSE(calculator_ui.encountered_error()); - // Close the other side of the pipe. - delete calculator; + // Close the server. + server->internal_state()->router()->CloseMessagePipe(); // The state change isn't picked up locally yet. EXPECT_FALSE(calculator_ui.encountered_error()); @@ -186,13 +197,14 @@ TEST_F(RemotePtrTest, EncounteredError) { EXPECT_TRUE(calculator_ui.encountered_error()); } -TEST_F(RemotePtrTest, EncounteredErrorCallback) { - MathCalculatorImpl* calculator = - new MathCalculatorImpl(pipe_.handle_to_self.Pass()); +TEST_F(InterfacePtrTest, EncounteredErrorCallback) { + math::CalculatorPtr proxy; + MathCalculatorImpl* server = BindToProxy(new MathCalculatorImpl(), &proxy); ErrorObserver error_observer; - MathCalculatorUIImpl calculator_ui(pipe_.handle_to_peer.Pass(), - &error_observer); + proxy.set_error_handler(&error_observer); + + MathCalculatorUIImpl calculator_ui(proxy.Pass()); calculator_ui.Add(2.0); PumpMessages(); @@ -202,8 +214,8 @@ TEST_F(RemotePtrTest, EncounteredErrorCallback) { calculator_ui.Multiply(5.0); EXPECT_FALSE(calculator_ui.encountered_error()); - // Close the other side of the pipe. - delete calculator; + // Close the server. + server->internal_state()->router()->CloseMessagePipe(); // The state change isn't picked up locally yet. EXPECT_FALSE(calculator_ui.encountered_error()); @@ -218,11 +230,12 @@ TEST_F(RemotePtrTest, EncounteredErrorCallback) { EXPECT_TRUE(error_observer.encountered_error()); } -TEST_F(RemotePtrTest, NoPeerAttribute) { +TEST_F(InterfacePtrTest, NoClientAttribute) { // This is a test to ensure the following compiles. The sample::Port interface - // does not have an explicit Peer attribute. - InterfacePipe<sample::Port, NoInterface> pipe; - RemotePtr<sample::Port> port(pipe.handle_to_self.Pass(), NULL); + // does not have an explicit Client attribute. + sample::PortPtr port; + MessagePipe pipe; + port.Bind(pipe.handle0.Pass()); } } // namespace diff --git a/mojo/public/cpp/bindings/tests/request_response_unittest.cc b/mojo/public/cpp/bindings/tests/request_response_unittest.cc index 94ed91f..d163f7d 100644 --- a/mojo/public/cpp/bindings/tests/request_response_unittest.cc +++ b/mojo/public/cpp/bindings/tests/request_response_unittest.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "mojo/public/cpp/bindings/allocation_scope.h" -#include "mojo/public/cpp/bindings/remote_ptr.h" #include "mojo/public/cpp/environment/environment.h" #include "mojo/public/cpp/test_support/test_utils.h" #include "mojo/public/cpp/utility/run_loop.h" @@ -15,10 +14,14 @@ namespace mojo { namespace test { namespace { -class ProviderImpl : public sample::Provider { +class ProviderImpl : public InterfaceImpl<sample::Provider> { public: - explicit ProviderImpl(sample::ScopedProviderClientHandle handle) - : client_(handle.Pass(), this) { + virtual void OnConnectionError() MOJO_OVERRIDE { + delete this; + } + + virtual void SetClient(sample::ProviderClient* client) MOJO_OVERRIDE { + // Ignored. TODO(darin): Eliminate ProviderClient. } virtual void EchoString( @@ -51,9 +54,6 @@ class ProviderImpl : public sample::Provider { MOJO_OVERRIDE { callback.Run(a); } - - private: - RemotePtr<sample::ProviderClient> client_; }; class StringRecorder { @@ -94,6 +94,10 @@ class MessagePipeWriter { class RequestResponseTest : public testing::Test { public: + virtual ~RequestResponseTest() { + loop_.RunUntilIdle(); + } + void PumpMessages() { loop_.RunUntilIdle(); } @@ -104,9 +108,8 @@ class RequestResponseTest : public testing::Test { }; TEST_F(RequestResponseTest, EchoString) { - InterfacePipe<sample::Provider> pipe; - ProviderImpl provider_impl(pipe.handle_to_peer.Pass()); - RemotePtr<sample::Provider> provider(pipe.handle_to_self.Pass(), NULL); + sample::ProviderPtr provider; + BindToProxy(new ProviderImpl(), &provider); std::string buf; { @@ -120,9 +123,8 @@ TEST_F(RequestResponseTest, EchoString) { } TEST_F(RequestResponseTest, EchoStrings) { - InterfacePipe<sample::Provider> pipe; - ProviderImpl provider_impl(pipe.handle_to_peer.Pass()); - RemotePtr<sample::Provider> provider(pipe.handle_to_self.Pass(), NULL); + sample::ProviderPtr provider; + BindToProxy(new ProviderImpl(), &provider); std::string buf; { @@ -136,9 +138,8 @@ TEST_F(RequestResponseTest, EchoStrings) { } TEST_F(RequestResponseTest, EchoMessagePipeHandle) { - InterfacePipe<sample::Provider> pipe; - ProviderImpl provider_impl(pipe.handle_to_peer.Pass()); - RemotePtr<sample::Provider> provider(pipe.handle_to_self.Pass(), NULL); + sample::ProviderPtr provider; + BindToProxy(new ProviderImpl(), &provider); MessagePipe pipe2; { @@ -156,9 +157,8 @@ TEST_F(RequestResponseTest, EchoMessagePipeHandle) { } TEST_F(RequestResponseTest, EchoEnum) { - InterfacePipe<sample::Provider> pipe; - ProviderImpl provider_impl(pipe.handle_to_peer.Pass()); - RemotePtr<sample::Provider> provider(pipe.handle_to_self.Pass(), NULL); + sample::ProviderPtr provider; + BindToProxy(new ProviderImpl(), &provider); sample::Enum value; { diff --git a/mojo/public/cpp/bindings/tests/sample_service_unittest.cc b/mojo/public/cpp/bindings/tests/sample_service_unittest.cc index 9a4cf36..c13517d 100644 --- a/mojo/public/cpp/bindings/tests/sample_service_unittest.cc +++ b/mojo/public/cpp/bindings/tests/sample_service_unittest.cc @@ -266,7 +266,14 @@ void DumpHex(const uint8_t* bytes, uint32_t num_bytes) { class ServiceImpl : public Service { public: - virtual void Frobinate(const Foo& foo, BazOptions baz, ScopedPortHandle port) + ServiceImpl() : client_(NULL) { + } + + virtual void SetClient(ServiceClient* client) MOJO_OVERRIDE { + client_ = client; + } + + virtual void Frobinate(const Foo& foo, BazOptions baz, PortPtr port) MOJO_OVERRIDE { // Users code goes here to handle the incoming Frobinate message. @@ -283,6 +290,20 @@ class ServiceImpl : public Service { Print(depth, "port", port.get()); } } + + private: + ServiceClient* client_; +}; + +class ServiceProxyImpl : public ServiceProxy { + public: + explicit ServiceProxyImpl(mojo::MessageReceiver* receiver) + : ServiceProxy(receiver) { + } + + virtual void SetClient(ServiceClient* client) MOJO_OVERRIDE { + assert(false); + } }; class SimpleMessageReceiver : public mojo::MessageReceiver { @@ -299,7 +320,8 @@ class SimpleMessageReceiver : public mojo::MessageReceiver { // the system. It receives the incoming message. ServiceImpl impl; - ServiceStub stub(&impl); + ServiceStub stub; + stub.set_sink(&impl); return stub.Accept(message); } @@ -315,7 +337,7 @@ TEST(BindingsSampleTest, Basic) { SimpleMessageReceiver receiver; // User has a proxy to a Service somehow. - Service* service = new ServiceProxy(&receiver); + Service* service = new ServiceProxyImpl(&receiver); // User constructs a message to send. @@ -328,8 +350,8 @@ TEST(BindingsSampleTest, Basic) { Foo foo = MakeFoo(); CheckFoo(foo); - mojo::InterfacePipe<Port, mojo::AnyInterface> pipe; - service->Frobinate(foo, Service::BAZ_EXTRA, pipe.handle_to_self.Pass()); + PortPtr port; + service->Frobinate(foo, Service::BAZ_EXTRA, port.Pass()); } TEST(BindingsSampleTest, DefaultValues) { diff --git a/mojo/public/cpp/shell/application.h b/mojo/public/cpp/shell/application.h index ffca7fe..933077b 100644 --- a/mojo/public/cpp/shell/application.h +++ b/mojo/public/cpp/shell/application.h @@ -7,7 +7,6 @@ #include <vector> -#include "mojo/public/cpp/bindings/remote_ptr.h" #include "mojo/public/cpp/shell/service.h" #include "mojo/public/cpp/system/core.h" #include "mojo/public/interfaces/shell/shell.mojom.h" @@ -16,7 +15,7 @@ namespace mojo { class Application : public internal::ServiceConnectorBase::Owner { public: - explicit Application(ScopedShellHandle shell_handle); + explicit Application(ScopedMessagePipeHandle shell_handle); explicit Application(MojoHandle shell_handle); virtual ~Application(); @@ -27,6 +26,11 @@ class Application : public internal::ServiceConnectorBase::Owner { virtual void RemoveServiceConnector( internal::ServiceConnectorBase* service_connector) MOJO_OVERRIDE; + template <typename Interface> + void ConnectTo(const std::string& url, InterfacePtr<Interface>* ptr) { + mojo::ConnectTo(shell(), url, ptr); + } + protected: // ShellClient methods. virtual void AcceptConnection(const mojo::String& url, diff --git a/mojo/public/cpp/shell/lib/application.cc b/mojo/public/cpp/shell/lib/application.cc index 3224202..161e4e0 100644 --- a/mojo/public/cpp/shell/lib/application.cc +++ b/mojo/public/cpp/shell/lib/application.cc @@ -6,13 +6,13 @@ namespace mojo { -Application::Application(ScopedShellHandle shell_handle) +Application::Application(ScopedMessagePipeHandle shell_handle) : internal::ServiceConnectorBase::Owner(shell_handle.Pass()) { } Application::Application(MojoHandle shell_handle) : internal::ServiceConnectorBase::Owner( - mojo::MakeScopedHandle(ShellHandle(shell_handle)).Pass()) {} + mojo::MakeScopedHandle(MessagePipeHandle(shell_handle)).Pass()) {} Application::~Application() { for (ServiceConnectorList::iterator it = service_connectors_.begin(); diff --git a/mojo/public/cpp/shell/lib/service.cc b/mojo/public/cpp/shell/lib/service.cc index e408481..2f2e542 100644 --- a/mojo/public/cpp/shell/lib/service.cc +++ b/mojo/public/cpp/shell/lib/service.cc @@ -7,8 +7,9 @@ namespace mojo { namespace internal { -ServiceConnectorBase::Owner::Owner(ScopedShellHandle shell_handle) - : shell_(shell_handle.Pass(), this) { +ServiceConnectorBase::Owner::Owner(ScopedMessagePipeHandle shell_handle) + : shell_(MakeProxy<Shell>(shell_handle.Pass())) { + shell_->SetClient(this); } ServiceConnectorBase::Owner::~Owner() {} diff --git a/mojo/public/cpp/shell/service.h b/mojo/public/cpp/shell/service.h index 7dd08ff..c546289 100644 --- a/mojo/public/cpp/shell/service.h +++ b/mojo/public/cpp/shell/service.h @@ -5,11 +5,11 @@ #ifndef MOJO_PUBLIC_SHELL_SERVICE_H_ #define MOJO_PUBLIC_SHELL_SERVICE_H_ +#include <assert.h> + #include <vector> -#include "mojo/public/cpp/bindings/error_handler.h" -#include "mojo/public/cpp/bindings/remote_ptr.h" -#include "mojo/public/cpp/system/core.h" +#include "mojo/public/cpp/bindings/allocation_scope.h" #include "mojo/public/interfaces/shell/shell.mojom.h" // Utility classes for creating ShellClients that vend service instances. @@ -19,11 +19,9 @@ // class FooImpl : public Foo { // public: // FooImpl(); -// void Initialize(ServiceConnector<FooImpl>* service_connector, -// ScopedMessagePipeHandle client_handle +// void Initialize(); // private: // ServiceConnector<FooImpl>* service_connector_; -// RemotePtr<FooPeer> client_; // }; // // @@ -66,8 +64,8 @@ class ServiceConnectorBase { public: class Owner : public ShellClient { public: - Owner(ScopedShellHandle shell_handle); - ~Owner(); + Owner(ScopedMessagePipeHandle shell_handle); + virtual ~Owner(); Shell* shell() { return shell_.get(); } virtual void AddServiceConnector( internal::ServiceConnectorBase* service_connector) = 0; @@ -79,7 +77,7 @@ class ServiceConnectorBase { Owner* owner) { service_connector->owner_ = owner; } - RemotePtr<Shell> shell_; + ShellPtr shell_; }; ServiceConnectorBase() : owner_(NULL) {} virtual ~ServiceConnectorBase(); @@ -98,27 +96,33 @@ class ServiceConnector : public internal::ServiceConnectorBase { ServiceConnector(Context* context = NULL) : context_(context) {} virtual ~ServiceConnector() { - for (typename ServiceList::iterator it = services_.begin(); - it != services_.end(); ++it) { + ConnectionList doomed; + doomed.swap(connections_); + for (typename ConnectionList::iterator it = doomed.begin(); + it != doomed.end(); ++it) { delete *it; } + assert(connections_.empty()); // No one should have added more! } virtual void AcceptConnection(const std::string& url, - ScopedMessagePipeHandle client_handle) - MOJO_OVERRIDE { - ServiceImpl* service = new ServiceImpl(); - service->Initialize(this, client_handle.Pass()); - services_.push_back(service); + ScopedMessagePipeHandle handle) MOJO_OVERRIDE { + ServiceImpl* impl = BindToPipe(new ServiceImpl(), handle.Pass()); + impl->set_connector(this); + + connections_.push_back(impl); + + impl->Initialize(); } - void RemoveService(ServiceImpl* service) { - for (typename ServiceList::iterator it = services_.begin(); - it != services_.end(); ++it) { - if (*it == service) { - services_.erase(it); - delete service; - if (services_.empty()) + void RemoveConnection(ServiceImpl* impl) { + // Called from ~ServiceImpl, in response to a connection error. + for (typename ConnectionList::iterator it = connections_.begin(); + it != connections_.end(); ++it) { + if (*it == impl) { + delete impl; + connections_.erase(it); + if (connections_.empty()) owner_->RemoveServiceConnector(this); return; } @@ -128,58 +132,63 @@ class ServiceConnector : public internal::ServiceConnectorBase { Context* context() const { return context_; } private: - typedef std::vector<ServiceImpl*> ServiceList; - ServiceList services_; + typedef std::vector<ServiceImpl*> ConnectionList; + ConnectionList connections_; Context* context_; }; // Specialization of ServiceConnection. // ServiceInterface: Service interface. -// ServiceImpl: Implementation of Service interface. +// ServiceImpl: Subclass of ServiceConnection<...>. // Context: Optional type of shared context. template <class ServiceInterface, class ServiceImpl, typename Context=void> -class ServiceConnection : public ServiceInterface { - public: +class ServiceConnection : public InterfaceImpl<ServiceInterface> { + protected: + // NOTE: shell() and context() are not available at construction time. + // Initialize() will be called once those are available. + ServiceConnection() : service_connector_(NULL) {} + virtual ~ServiceConnection() {} - protected: - ServiceConnection() : reaper_(this), service_connector_(NULL) {} - - void Initialize(ServiceConnector<ServiceImpl, Context>* service_connector, - ScopedMessagePipeHandle client_handle) { - service_connector_ = service_connector; - client_.reset( - MakeScopedHandle( - InterfaceHandle<typename ServiceInterface::_Peer>( - client_handle.release().value())).Pass(), - this, - &reaper_); + virtual void OnConnectionError() MOJO_OVERRIDE { + service_connector_->RemoveConnection(static_cast<ServiceImpl*>(this)); + } + + // Shadow this method in ServiceImpl to perform one-time initialization. + // At the time this is called, shell() and context() will be available. + // NOTE: No need to call the base class Initialize from your subclass. It + // will always be a no-op. + void Initialize() {} + + Shell* shell() { + return service_connector_->shell(); } - Shell* shell() { return service_connector_->shell(); } - Context* context() const { return service_connector_->context(); } - typename ServiceInterface::_Peer* client() { return client_.get(); } + Context* context() const { + return service_connector_->context(); + } private: - // The Reaper class allows us to handle errors on the client proxy without - // polluting the name space of the ServiceConnection<> class. - class Reaper : public ErrorHandler { - public: - Reaper(ServiceConnection<ServiceInterface, ServiceImpl, Context>* service) - : service_(service) {} - virtual void OnError() { - service_->service_connector_->RemoveService( - static_cast<ServiceImpl*>(service_)); - } - private: - ServiceConnection<ServiceInterface, ServiceImpl, Context>* service_; - }; friend class ServiceConnector<ServiceImpl, Context>; - Reaper reaper_; + + // Called shortly after this class is instantiated. + void set_connector(ServiceConnector<ServiceImpl, Context>* connector) { + service_connector_ = connector; + } + ServiceConnector<ServiceImpl, Context>* service_connector_; - RemotePtr<typename ServiceInterface::_Peer> client_; }; +template <typename Interface> +inline void ConnectTo(Shell* shell, const std::string& url, + InterfacePtr<Interface>* ptr) { + MessagePipe pipe; + ptr->Bind(pipe.handle0.Pass()); + + AllocationScope scope; + shell->Connect(url, pipe.handle1.Pass()); +} + } // namespace mojo #endif // MOJO_PUBLIC_SHELL_SERVICE_H_ diff --git a/mojo/public/interfaces/bindings/tests/math_calculator.mojom b/mojo/public/interfaces/bindings/tests/math_calculator.mojom index e4a1c94..63b7a69 100644 --- a/mojo/public/interfaces/bindings/tests/math_calculator.mojom +++ b/mojo/public/interfaces/bindings/tests/math_calculator.mojom @@ -5,14 +5,13 @@ [JavaPackage="org.chromium.mojo.bindings.test"] module math { -[Peer=CalculatorUI] +[Client=CalculatorUI] interface Calculator { Clear@0(); Add@1(double value @0); Multiply@2(double value @0); }; -[Peer=Calculator] interface CalculatorUI { Output@0(double value @0); }; diff --git a/mojo/public/interfaces/bindings/tests/sample_factory.mojom b/mojo/public/interfaces/bindings/tests/sample_factory.mojom index bad466f..33de19f 100644 --- a/mojo/public/interfaces/bindings/tests/sample_factory.mojom +++ b/mojo/public/interfaces/bindings/tests/sample_factory.mojom @@ -19,13 +19,12 @@ struct Response { handle<message_pipe> pipe; }; -[Peer=FactoryClient] +[Client=FactoryClient] interface Factory { DoStuff(Request request, handle<message_pipe> pipe); DoStuff2(handle<data_pipe_consumer> pipe); }; -[Peer=Factory] interface FactoryClient { DidStuff(Response response, string text); DidStuff2(string text); diff --git a/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom b/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom index 462e3cd..597fd0d 100644 --- a/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom +++ b/mojo/public/interfaces/bindings/tests/sample_interfaces.mojom @@ -10,7 +10,7 @@ enum Enum { ENUM_VALUE }; -[Peer=ProviderClient] +[Client=ProviderClient] interface Provider { EchoString(string a) => (string a); EchoStrings(string a, string b) => (string a, string b); @@ -18,7 +18,7 @@ interface Provider { EchoEnum(Enum a) => (Enum a); }; -[Peer=Provider] +// TODO(darin): We shouldn't need this, but JS bindings don't work without it. interface ProviderClient { }; diff --git a/mojo/public/interfaces/bindings/tests/sample_service.mojom b/mojo/public/interfaces/bindings/tests/sample_service.mojom index 0336998..c840709 100644 --- a/mojo/public/interfaces/bindings/tests/sample_service.mojom +++ b/mojo/public/interfaces/bindings/tests/sample_service.mojom @@ -53,7 +53,7 @@ struct DefaultsTest { Bar.Type bar_type = Bar.TYPE_BOTH; }; -[Peer=ServiceClient] +[Client=ServiceClient] interface Service { enum BazOptions { BAZ_REGULAR = 0, @@ -62,7 +62,6 @@ interface Service { Frobinate@0(Foo foo @0, BazOptions baz @1, Port port @2); }; -[Peer=Service] interface ServiceClient { DidFrobinate@0(int32 result @0); }; @@ -70,7 +69,7 @@ interface ServiceClient { // This interface is referenced above where it is defined. It also refers to // itself from a method. interface Port { - PostMessage@0(string message_text @0, Port[] extra_ports@1); + PostMessage@0(string message_text @0, Port port@1); }; } diff --git a/mojo/public/interfaces/shell/shell.mojom b/mojo/public/interfaces/shell/shell.mojom index 39eae78..e5f6c39 100644 --- a/mojo/public/interfaces/shell/shell.mojom +++ b/mojo/public/interfaces/shell/shell.mojom @@ -4,14 +4,13 @@ module mojo { -[Peer=ShellClient] +[Client=ShellClient] interface Shell { // Loads url. mojo:{service} will result in the user of the value of the // --origin flag to the shell being used. Connect(string url, handle<message_pipe> client_handle); }; -[Peer=Shell] interface ShellClient { AcceptConnection(string url, handle<message_pipe> client_handle); }; diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl index 60fbfc5..d1c7e53 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_declaration.tmpl @@ -1,18 +1,18 @@ {%- import "interface_macros.tmpl" as interface_macros %} class {{interface.name}}Proxy; class {{interface.name}}Stub; -{% if interface.peer %} -class {{interface.peer}}; +{% if interface.client %} +class {{interface.client}}; {% endif %} class {{interface.name}} { public: - typedef {{interface.name}}Proxy _Proxy; - typedef {{interface.name}}Stub _Stub; -{% if interface.peer %} - typedef {{interface.peer}} _Peer; + typedef {{interface.name}}Proxy Proxy_; + typedef {{interface.name}}Stub Stub_; +{% if interface.client %} + typedef {{interface.client}} Client_; {% else %} - typedef mojo::NoInterface _Peer; + typedef mojo::NoInterface Client_; {% endif %} {#--- Enums #} @@ -22,6 +22,13 @@ class {{interface.name}} { {%- endfor %} {#--- Methods #} + virtual ~{{interface.name}}() {} +{%- if interface.client %} + // Called once before any other method. + virtual void SetClient({{interface.client}}* client) = 0; +{%- else %} + virtual void SetClient(mojo::NoInterface* client) {} +{%- endif %} {%- for method in interface.methods %} virtual void {{method.name}}({{interface_macros.declare_request_params("", method)}}) = 0; {%- endfor %} diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl index 7a03023..ccd4b42 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl @@ -6,6 +6,8 @@ {%- for param in parameters %} {%- if param.kind|is_object_kind -%} mojo::internal::Wrap(params->{{param.name}}()) +{%- elif param.kind|is_interface_kind -%} +mojo::MakeProxy<{{param.kind.name}}>(mojo::MakePassable(params->{{param.name}}()).Pass()) {%- elif param.kind|is_handle_kind -%} mojo::MakePassable(params->{{param.name}}()).Pass() {%- elif param.kind|is_enum_kind -%} @@ -38,6 +40,14 @@ params->{{param.name}}() if (!in_{{param.name}}.is_null()) params->set_{{param.name}}( mojo::internal::Unwrap(in_{{param.name}})->Clone(builder.buffer())); +{%- elif param.kind|is_interface_kind %} + if (!in_{{param.name}}.get()) { + params->set_{{param.name}}(mojo::MessagePipeHandle()); + } else { + // Delegate handle. + params->set_{{param.name}}( + in_{{param.name}}.ResetAndReturnMessagePipe().release()); + } {%- elif param.kind|is_handle_kind %} params->set_{{param.name}}(in_{{param.name}}.release()); {%- else %} @@ -165,8 +175,8 @@ void {{class_name}}_{{method.name}}_ProxyToResponder::Run( {%- endif -%} {%- endfor %} -{{class_name}}Stub::{{class_name}}Stub({{class_name}}* sink) - : sink_(sink) { +{{class_name}}Stub::{{class_name}}Stub() + : sink_(NULL) { } {#--- Stub definition #} diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl index c4a8bed..b9cf4bc 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_proxy_declaration.tmpl @@ -3,6 +3,12 @@ class {{interface.name}}Proxy : public {{interface.name}} { public: explicit {{interface.name}}Proxy(mojo::MessageReceiver* receiver); +{%- if interface.client %} + virtual void SetClient({{interface.client}}* client) = 0; +{%- else %} + virtual void SetClient(mojo::NoInterface* client) {} +{%- endif %} + {%- for method in interface.methods %} virtual void {{method.name}}( {{interface_macros.declare_request_params("", method)}} diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl index 0e4b202..b435d5d 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_stub_declaration.tmpl @@ -1,6 +1,8 @@ class {{interface.name}}Stub : public mojo::MessageReceiver { public: - explicit {{interface.name}}Stub({{interface.name}}* sink); + {{interface.name}}Stub(); + void set_sink({{interface.name}}* sink) { sink_ = sink; } + {{interface.name}}* sink() { return sink_; } virtual bool Accept(mojo::Message* message) MOJO_OVERRIDE; virtual bool AcceptWithResponder(mojo::Message* message, diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl index 4c667ae..6a0f6cf 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/module.h.tmpl @@ -10,7 +10,9 @@ #include "mojo/public/cpp/bindings/array.h" #include "mojo/public/cpp/bindings/callback.h" -#include "mojo/public/cpp/bindings/interface.h" +#include "mojo/public/cpp/bindings/interface_impl.h" +#include "mojo/public/cpp/bindings/interface_ptr.h" +#include "mojo/public/cpp/bindings/no_interface.h" #include "{{module.path}}-internal.h" {%- for import in imports %} #include "{{import.module.path}}.h" @@ -28,10 +30,7 @@ namespace {{namespace}} { {#--- Interface Forward Declarations -#} {% for interface in interfaces %} class {{interface.name}}; -// A typesafe variant of MessagePipeHandle: -typedef mojo::Interface<{{interface.name}}>::Handle {{interface.name}}Handle; -// A typesafe variant of ScopedMessagePipeHandle: -typedef mojo::Interface<{{interface.name}}>::ScopedHandle Scoped{{interface.name}}Handle; +typedef mojo::InterfacePtr<{{interface.name}}> {{interface.name}}Ptr; {% endfor %} {#--- Structs #} diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py index 8f48f8e..3996d5e 100644 --- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py @@ -50,7 +50,7 @@ def GetCppType(kind): if isinstance(kind, mojom.Array): return "mojo::internal::Array_Data<%s>*" % GetCppType(kind.kind) if isinstance(kind, mojom.Interface): - return "%sHandle" % kind.name + return "mojo::MessagePipeHandle" if isinstance(kind, mojom.Enum): return "int32_t" if kind.spec == 's': @@ -63,7 +63,7 @@ def GetCppArrayArgWrapperType(kind): if isinstance(kind, mojom.Array): return "mojo::Array<%s >" % GetCppArrayArgWrapperType(kind.kind) if isinstance(kind, mojom.Interface): - return "%sHandle" % kind.name + raise Exception("Arrays of interfaces not yet supported!") if kind.spec == 's': return "mojo::String" return _kind_to_cpp_type[kind] @@ -74,7 +74,7 @@ def GetCppResultWrapperType(kind): if isinstance(kind, mojom.Array): return "mojo::Array<%s >" % GetCppArrayArgWrapperType(kind.kind) if isinstance(kind, mojom.Interface): - return "Scoped%sHandle" % kind.name + return "%sPtr" % kind.name if kind.spec == 's': return "mojo::String" if kind.spec == 'h': @@ -95,7 +95,7 @@ def GetCppWrapperType(kind): if isinstance(kind, mojom.Array): return "mojo::Array<%s >" % GetCppArrayArgWrapperType(kind.kind) if isinstance(kind, mojom.Interface): - return "mojo::Passable<%sHandle>" % kind.name + return "mojo::Passable<mojo::MessagePipeHandle>" if kind.spec == 's': return "mojo::String" if generator.IsHandleKind(kind): @@ -108,7 +108,7 @@ def GetCppConstWrapperType(kind): if isinstance(kind, mojom.Array): return "const mojo::Array<%s >&" % GetCppArrayArgWrapperType(kind.kind) if isinstance(kind, mojom.Interface): - return "Scoped%sHandle" % kind.name + return "%sPtr" % kind.name if isinstance(kind, mojom.Enum): return GetNameForKind(kind) if kind.spec == 's': @@ -134,7 +134,7 @@ def GetCppFieldType(kind): if isinstance(kind, mojom.Array): return "mojo::internal::ArrayPointer<%s>" % GetCppType(kind.kind) if isinstance(kind, mojom.Interface): - return "%sHandle" % kind.name + return "mojo::MessagePipeHandle" if isinstance(kind, mojom.Enum): return GetNameForKind(kind) if kind.spec == 's': @@ -180,6 +180,7 @@ class Generator(generator.Generator): "get_pad": pack.GetPad, "is_enum_kind": generator.IsEnumKind, "is_handle_kind": generator.IsHandleKind, + "is_interface_kind": generator.IsInterfaceKind, "is_object_kind": generator.IsObjectKind, "is_string_kind": generator.IsStringKind, "is_array_kind": lambda kind: isinstance(kind, mojom.Array), diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/data.py b/mojo/public/tools/bindings/pylib/mojom/generate/data.py index 1f2f808..2199782 100644 --- a/mojo/public/tools/bindings/pylib/mojom/generate/data.py +++ b/mojo/public/tools/bindings/pylib/mojom/generate/data.py @@ -221,7 +221,7 @@ def MethodFromData(module, data, interface): def InterfaceToData(interface): return { istr(0, 'name'): interface.name, - istr(1, 'peer'): interface.peer, + istr(1, 'client'): interface.client, istr(2, 'methods'): map(MethodToData, interface.methods) } @@ -229,7 +229,7 @@ def InterfaceFromData(module, data): interface = mojom.Interface(module=module) interface.name = data['name'] interface.spec = 'x:' + module.namespace + '.' + interface.name - interface.peer = data['peer'] if data.has_key('peer') else None + interface.client = data['client'] if data.has_key('client') else None module.kinds[interface.spec] = interface interface.enums = map(lambda enum: EnumFromData(module, enum, interface), data['enums']) diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py b/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py index bca7ed8..096554c 100644 --- a/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py +++ b/mojo/public/tools/bindings/pylib/mojom/generate/data_tests.py @@ -44,7 +44,7 @@ test_dict = { {'name': 'testfield2', 'kind': 'a:i32', 'ordinal': 42}]}], 'interfaces': [{ 'name': 'Server', - 'peer': None, + 'client': None, 'methods': [{ 'name': 'Foo', 'parameters': [ diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/generator.py b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py index 709aa2a..76e5998 100644 --- a/mojo/public/tools/bindings/pylib/mojom/generate/generator.py +++ b/mojo/public/tools/bindings/pylib/mojom/generate/generator.py @@ -46,6 +46,9 @@ def IsObjectKind(kind): def IsHandleKind(kind): return kind.spec.startswith('h') or isinstance(kind, mojom.Interface) +def IsInterfaceKind(kind): + return isinstance(kind, mojom.Interface) + def StudlyCapsToCamel(studly): return studly[0].lower() + studly[1:] diff --git a/mojo/public/tools/bindings/pylib/mojom/generate/module.py b/mojo/public/tools/bindings/pylib/mojom/generate/module.py index 4abe690..875ede9 100644 --- a/mojo/public/tools/bindings/pylib/mojom/generate/module.py +++ b/mojo/public/tools/bindings/pylib/mojom/generate/module.py @@ -139,7 +139,7 @@ class Method(object): class Interface(Kind): - def __init__(self, name=None, peer=None, module=None): + def __init__(self, name=None, client=None, module=None): self.module = module self.name = name if name != None: @@ -147,7 +147,7 @@ class Interface(Kind): else: spec = None Kind.__init__(self, spec) - self.peer = peer + self.client = client self.methods = [] def AddMethod(self, name, ordinal=None): diff --git a/mojo/public/tools/bindings/pylib/mojom/parse/translate.py b/mojo/public/tools/bindings/pylib/mojom/parse/translate.py index 2300cb6..b363d9c 100644 --- a/mojo/public/tools/bindings/pylib/mojom/parse/translate.py +++ b/mojo/public/tools/bindings/pylib/mojom/parse/translate.py @@ -88,7 +88,7 @@ def _MapStruct(tree): def _MapInterface(tree): interface = {} interface['name'] = tree[1] - interface['peer'] = _GetAttribute(tree[2], 'Peer') + interface['client'] = _GetAttribute(tree[2], 'Client') interface['methods'] = _MapTree(_MapMethod, tree[3], 'METHOD') interface['enums'] = _MapTree(_MapEnum, tree[3], 'ENUM') return interface |