blob: 11965c4f371f27125f471a3f077af8fff75f8c2f [file] [log] [blame]
// Copyright 2016 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_SYNCHRONOUS_INTERFACE_PTR_H_
#define MOJO_PUBLIC_CPP_BINDINGS_SYNCHRONOUS_INTERFACE_PTR_H_
#include <cstddef>
#include <memory>
#include <utility>
#include "mojo/public/cpp/bindings/interface_handle.h"
#include "mojo/public/cpp/bindings/lib/message_header_validator.h"
#include "mojo/public/cpp/bindings/lib/synchronous_connector.h"
#include "mojo/public/cpp/bindings/message_validator.h"
#include "mojo/public/cpp/environment/logging.h"
#include "mojo/public/cpp/system/macros.h"
namespace mojo {
// A synchronous version of InterfacePtr. Interface message calls using a
// SynchronousInterfacePtr will block if a response message is expected. This
// class uses the generated synchronous versions of the mojo interfaces.
//
// To make a SynchronousInterfacePtr, use the |Create()| factory method and
// supply the InterfaceHandle to it. Use |PassInterfaceHandle()| to extract the
// InterfaceHandle.
//
// SynchronousInterfacePtr is thread-compatible (but not thread-safe).
//
// TODO(vardhan): Add support for InterfaceControlMessage methods.
// TODO(vardhan): Message calls invoked on this class will return |false| if
// there are any message pipe errors. Should there be a better way to expose
// underlying message pipe errors?
template <typename Interface>
class SynchronousInterfacePtr {
public:
// Constructs an unbound SynchronousInterfacePtr.
SynchronousInterfacePtr() : version_(0) {}
SynchronousInterfacePtr(std::nullptr_t) : SynchronousInterfacePtr() {}
// Takes over the binding of another SynchronousInterfacePtr, and closes any
// message pipe already bound to this pointer.
SynchronousInterfacePtr(SynchronousInterfacePtr&& other) = default;
// Takes over the binding of another SynchronousInterfacePtr, and closes any
// message pipe already bound to this pointer.
SynchronousInterfacePtr& operator=(SynchronousInterfacePtr&& other) = default;
static SynchronousInterfacePtr<Interface> Create(
InterfaceHandle<Interface> handle) {
return SynchronousInterfacePtr<Interface>(std::move(handle));
}
// Closes the bound message pipe (if any).
void reset() { *this = SynchronousInterfacePtr<Interface>(); }
// Returns a raw pointer to the local proxy. Caller does not take ownership.
// Note that the local proxy is thread hostile, as stated above.
typename Interface::Synchronous_* get() { return proxy_.get(); }
typename Interface::Synchronous_* operator->() {
MOJO_DCHECK(connector_);
MOJO_DCHECK(proxy_);
return proxy_.get();
}
typename Interface::Synchronous_& operator*() { return *operator->(); }
// Returns whether or not this SynchronousInterfacePtr is bound to a message
// pipe.
bool is_bound() const { return connector_ && connector_->is_valid(); }
explicit operator bool() const { return is_bound(); }
uint32_t version() const { return version_; }
// Unbinds the SynchronousInterfacePtr and returns the underlying
// InterfaceHandle for the interface.
InterfaceHandle<Interface> PassInterfaceHandle() {
InterfaceHandle<Interface> handle(connector_->PassHandle(), version_);
reset();
return handle;
}
private:
// We save the version_ here before we pass the underlying message pipe handle
// to |connector_|.
uint32_t version_;
// A simple I/O interface we supply to the generated |proxy_| so it doesn't
// have to know how to write mojo message.
std::unique_ptr<internal::SynchronousConnector> connector_;
// |proxy_| must outlive |connector_|, so make sure it is declared in this
// order.
std::unique_ptr<typename Interface::Synchronous_::Proxy_> proxy_;
SynchronousInterfacePtr(InterfaceHandle<Interface> handle)
: version_(handle.version()) {
connector_.reset(new internal::SynchronousConnector(handle.PassHandle()));
mojo::internal::MessageValidatorList validators;
validators.push_back(std::unique_ptr<mojo::internal::MessageValidator>(
new mojo::internal::MessageHeaderValidator));
validators.push_back(std::unique_ptr<mojo::internal::MessageValidator>(
new typename Interface::ResponseValidator_));
proxy_.reset(new typename Interface::Synchronous_::Proxy_(
connector_.get(), std::move(validators)));
}
MOJO_MOVE_ONLY_TYPE(SynchronousInterfacePtr);
};
// Creates a new message pipe over which Interface is to be served. Binds the
// specified SynchronousInterfacePtr to one end of the message pipe, and returns
// an InterfaceRequest bound to the other. The SynchronousInterfacePtr should be
// passed to the client, and the InterfaceRequest should be passed to whatever
// will provide the implementation. Unlike InterfacePtr<>, invocations on
// SynchronousInterfacePtr<> will block until a response is received, so the
// user must pass off InterfaceRequest<> to an implementation before issuing any
// calls.
//
// Example:
// ========
// Given the following interface
// interface Echo {
// EchoString(string str) => (string value);
// }
//
// The client would have code similar to the following:
//
// SynchronousInterfacePtr<Echo> client;
// InterfaceRequest<Echo> impl = GetSynchronousProxy(&client);
// // .. pass |impl| off to an implementation.
// mojo::String out;
// client->EchoString("hello!", &out);
//
// TODO(vardhan): Consider renaming this function, along with her sister
// |GetProxy()| functions. Maybe `MakeSyncProxy()`?
template <typename Interface>
InterfaceRequest<Interface> GetSynchronousProxy(
SynchronousInterfacePtr<Interface>* ptr) {
InterfaceHandle<Interface> iface_handle;
auto retval = GetProxy(&iface_handle);
*ptr = SynchronousInterfacePtr<Interface>::Create(std::move(iface_handle));
return retval;
}
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_BINDINGS_SYNCHRONOUS_INTERFACE_PTR_H_