| Index: mojo/public/cpp/bindings/interface_ptr.h
|
| diff --git a/mojo/public/cpp/bindings/interface_ptr.h b/mojo/public/cpp/bindings/interface_ptr.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8f5157909709b858777a2ca8e3599ad670be713f
|
| --- /dev/null
|
| +++ b/mojo/public/cpp/bindings/interface_ptr.h
|
| @@ -0,0 +1,206 @@
|
| +// 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 <stdio.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 {
|
| +
|
| +template <typename T>
|
| +class InterfacePtr {
|
| + MOJO_MOVE_ONLY_TYPE_FOR_CPP_03(InterfacePtr, RValue)
|
| + public:
|
| + typedef T Interface;
|
| +
|
| + InterfacePtr() {}
|
| + explicit InterfacePtr(Interface* impl) { state_.impl = impl; }
|
| +
|
| + InterfacePtr(RValue other) { other.object->state_.Swap(&state_); }
|
| + InterfacePtr& operator=(RValue other) {
|
| + other.object->state_.Swap(&state_);
|
| + return *this;
|
| + }
|
| +
|
| + ~InterfacePtr() {}
|
| +
|
| + Interface* get() const {
|
| + return state_.impl;
|
| + }
|
| + Interface* operator->() const { return get(); }
|
| + Interface* operator*() const { return get(); }
|
| +
|
| + void reset() {
|
| + State doomed;
|
| + state_.Swap(&doomed);
|
| + }
|
| +
|
| + void Bind(Interface* impl) {
|
| + reset();
|
| + state_.impl = impl;
|
| + }
|
| +
|
| + bool encountered_error() const;
|
| +
|
| + void set_error_handler(ErrorHandler* error_handler);
|
| +
|
| + // XXX figure out how to hide these!
|
| +
|
| + bool has_context() const { return !!state_.context; }
|
| +
|
| + void ConfigureProxy(ScopedMessagePipeHandle handle,
|
| + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) {
|
| + assert(!state_.impl);
|
| + assert(!state_.context);
|
| +
|
| + internal::InterfacePtrContext* context =
|
| + new internal::InterfacePtrContext(handle.Pass(), waiter);
|
| + ProxyWithStub* proxy = new ProxyWithStub(context->router());
|
| + context->router()->set_incoming_receiver(&proxy->stub);
|
| +
|
| + state_.impl = proxy;
|
| + state_.context = context;
|
| + }
|
| +
|
| + void ConfigureStub(ScopedMessagePipeHandle handle,
|
| + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) {
|
| + assert(state_.impl); // Should have already been set!
|
| + assert(!state_.context);
|
| +
|
| + // Stub for binding to state_.impl
|
| + // Proxy for communicating to the client on the other end of the pipe.
|
| +
|
| + internal::InterfacePtrContext* context =
|
| + new internal::InterfacePtrContext(handle.Pass(), waiter);
|
| + ClientProxyWithStub* proxy = new ClientProxyWithStub(context->router());
|
| + proxy->stub.set_sink(state_.impl);
|
| + context->router()->set_incoming_receiver(&proxy->stub);
|
| +
|
| + state_.impl->SetClient(proxy);
|
| +
|
| + state_.client = proxy;
|
| + state_.context = context;
|
| + }
|
| +
|
| + void Detach() {
|
| + new DetachedState(&state_);
|
| + }
|
| +
|
| + private:
|
| + struct ProxyWithStub : public Interface::Proxy_ {
|
| + 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;
|
| + };
|
| +
|
| + struct ClientProxyWithStub : public Interface::Client_::Proxy_ {
|
| + explicit ClientProxyWithStub(MessageReceiver* receiver)
|
| + : Interface::Client_::Proxy_(receiver) {
|
| + }
|
| + typename Interface::Stub_ stub;
|
| + };
|
| +
|
| + struct State {
|
| + State() : impl(NULL), client(NULL), context(NULL) {}
|
| +
|
| + ~State() {
|
| + delete context; // context depends on impl
|
| + delete impl; // impl depends on client
|
| + delete client;
|
| + }
|
| +
|
| + void Swap(State* other) {
|
| + std::swap(other->impl, impl);
|
| + std::swap(other->client, client);
|
| + std::swap(other->context, context);
|
| + }
|
| +
|
| + Interface* impl;
|
| + typename Interface::Client_* client;
|
| + internal::InterfacePtrContext* context;
|
| +
|
| + MOJO_DISALLOW_COPY_AND_ASSIGN(State);
|
| + };
|
| +
|
| + class DetachedState : public ErrorHandler {
|
| + public:
|
| + explicit DetachedState(State* state) {
|
| + internal::LogDetachedState(this, +1);
|
| +
|
| + state_.Swap(state);
|
| +
|
| + assert(state_.context);
|
| + assert(!state_.context->router()->encountered_error());
|
| +
|
| + // Register to observe when the pipe is broken.
|
| + state_.context->router()->set_error_handler(this);
|
| + }
|
| +
|
| + virtual void OnError() MOJO_OVERRIDE {
|
| + internal::LogDetachedState(this, -1);
|
| +
|
| + delete this;
|
| + }
|
| +
|
| + State state_;
|
| + };
|
| +
|
| + State 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.
|
| +//
|
| +// XXX not sure if MakeProxy is the best name here.
|
| +template <typename Interface>
|
| +InterfacePtr<Interface> MakeProxy(
|
| + ScopedMessagePipeHandle handle,
|
| + MojoAsyncWaiter* waiter = GetDefaultAsyncWaiter()) {
|
| + InterfacePtr<Interface> ptr;
|
| + if (handle.is_valid())
|
| + ptr.ConfigureProxy(handle.Pass(), waiter);
|
| + return ptr.Pass();
|
| +}
|
| +
|
| +// Takes a heap-allocated interface implementation and binds its lifetime to
|
| +// that of a MessagePipe. A handle to the proxy end-point of the pipe is
|
| +// returned. If that pipe is closed, then the interface implementation will be
|
| +// deleted.
|
| +//
|
| +// The interface implementation 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 its end point of the pipe will be
|
| +// closed.
|
| +//
|
| +// Before returning the interface implementation will receive a SetClient call,
|
| +// providing it with a proxy to the client on the other end of the pipe.
|
| +//
|
| +// XXX not sure if BindToPipe is the best name here.
|
| +template <typename Interface>
|
| +ScopedMessagePipeHandle BindToPipe(Interface* impl) {
|
| + InterfacePtr<Interface> ptr(impl);
|
| + MessagePipe pipe;
|
| + ptr.ConfigureStub(pipe.handle0.Pass());
|
| + ptr.Detach();
|
| + return pipe.handle1.Pass();
|
| +}
|
| +
|
| +} // namespace mojo
|
| +
|
| +#endif // MOJO_PUBLIC_CPP_BINDINGS_INTERFACE_PTR_H_
|
|
|