blob: b0941fcbe8a71871488ca60cbb01b9884d49245b [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 LIB_FIDL_CPP_SYNCHRONOUS_INTERFACE_PTR_H_
#define LIB_FIDL_CPP_SYNCHRONOUS_INTERFACE_PTR_H_
#include <stddef.h>
#include <memory>
#include <utility>
#include "lib/fidl/cpp/interface_handle.h"
namespace fidl {
// A synchronous client interface to a remote implementation of |Interface|.
//
// An |SynchronousInterfacePtr| implements |Interface| by proxying calls through
// a |channel| to a remote implementation of |Interface|. Method calls on the
// |Interface| proxy are encoded and sent through the bound channel to the
// remote endpoint, which processes them. If the method has a reply (including
// any empty reply), the client blocks and waits for the remote endpoint to
// reply.
//
// You need to bind the |SynchronousInterfacePtr| before calling any |Interface|
// methods. There are a number of ways to bind the |SynchronousInterfacePtr|.
// See |NewRequest|, |Bind|, and the |BindSync| method on |InterfaceHandle|.
//
// This class is thread-compatible. Once bound, the |SynchronousInterfacePtr|
// can be used from multiple threads simultaneously. However, the
// |SynchronousInterfacePtr| does not attempt to synchronize mutating operatios,
// such as |Bind| or |Unbind|.
//
// |SynchronousInterfacePtr| does not require a |async_dispatcher_t|
// implementation and does not bind to the default |async_dispatcher_t*| for the
// current thread, unlike |InterfacePtr|.
//
// See also:
//
// * |Binding|, which is the server analog of an |SynchronousInterfacePtr|.
// * |InterfacePtr|, which is an asynchronous interface to a remote
// implementation.
template <typename Interface>
class SynchronousInterfacePtr final {
public:
using InterfaceSync = typename Interface::Sync_;
// Creates an unbound |SynchronousInterfacePtr|.
SynchronousInterfacePtr() {}
SynchronousInterfacePtr(std::nullptr_t) {}
SynchronousInterfacePtr(const SynchronousInterfacePtr& other) = delete;
SynchronousInterfacePtr& operator=(const SynchronousInterfacePtr& other) = delete;
SynchronousInterfacePtr(SynchronousInterfacePtr&& other) = default;
SynchronousInterfacePtr& operator=(SynchronousInterfacePtr&& other) = default;
// Bind the |SynchronousInterfacePtr| to one endpoint of a newly created
// channel and return the other endpoint as an |InterfaceRequest|.
//
// Typically, the returned |InterfaceRequest| will be sent to a remote process
// to be bound to an implementation of |Interface| using a |Binding| object.
//
// After calling this method, clients can start calling methods on this
// |SynchronousInterfacePtr|. However, methods that have replies will block
// until the remote implementation binds the |InterfaceRequest| and replies.
//
// # Example
//
// Given the following interface:
//
// interface Database {
// OpenTable(request<Table> table);
// };
//
// The client can use the |NewRequest| method to create the |InterfaceRequest|
// object needed by the |OpenTable| method:
//
// DatabasePtr database = ...; // Connect to database.
// TableSyncPtr table;
// database->OpenTable(table.NewRequest());
//
// The client can call methods on |table| immediately. Messages that have
// replies will block until the Database implementation binds a Table
// implementation and replies.
InterfaceRequest<Interface> NewRequest() {
zx::channel h1;
zx::channel h2;
if (zx::channel::create(0, &h1, &h2) != ZX_OK)
return nullptr;
Bind(std::move(h1));
return InterfaceRequest<Interface>(std::move(h2));
}
// Binds the |SynchronousInterfacePtr| to the given |channel|.
//
// The |SynchronousInterfacePtr| expects the remote end of the |channel| to
// speak the protocol defined by |Interface|. Unlike the |Bind| overload that
// takes a |InterfaceHandle| parameter, this |Bind| overload lacks type
// safety.
//
// If the |SynchronousInterfacePtr| was prevously bound to another channel,
// that channel is closed. If the |channel| is invalid, then this method will
// effectively unbind the |SynchronousInterfacePtr|. A more direct way to have
// that effect is to call |Unbind|.
//
// Does not require the current thread to have a default async_dispatcher_t.
void Bind(zx::channel channel) {
if (!channel) {
proxy_.reset();
return;
}
proxy_.reset(new typename InterfaceSync::Proxy_(std::move(channel)));
}
// Binds the |SynchronousInterfacePtr| to the given |InterfaceHandle|.
//
// The |SynchronousInterfacePtr| expects the remote end of the |channel| to
// speak the protocol defined by |Interface|. Unlike the |Bind| overload that
// takes a |channel| parameter, this |Bind| overload provides type safety.
//
// If the |SynchronousInterfacePtr| was prevously bound to another channel,
// that channel is closed. If the |InterfaceHandle| is invalid, then this
// method will effectively unbind the |SynchronousInterfacePtr|. A more direct
// way to have that effect is to call |Unbind|.
//
// Does not require the current thread to have a default async_dispatcher_t.
void Bind(InterfaceHandle<Interface> handle) { return Bind(handle.TakeChannel()); }
// Unbinds the underlying channel from the |SynchronousInterfacePtr|.
//
// The underlying channel is returned as an |InterfaceHandle|, which is safe
// to transport to another thread or process.
//
// After this method returns, a subsequent call to |Bind| is required before
// calling any additional |Interface| methods.
InterfaceHandle<Interface> Unbind() {
InterfaceHandle<Interface> handle(proxy_->proxy_.TakeChannel());
proxy_.reset();
return handle;
}
// Whether this |SynchronousInterfacePtr| is currently bound to a channel.
//
// If the |SynchronousInterfacePtr| is bound to a channel, calls to
// |Interface| methods are proxied to the remote endpoint of the channel.
//
// See also:
//
// * |Bind|, which binds a channel to this |SynchronousInterfacePtr|.
// * |Unbind|, which unbinds a channel from this |SynchronousInterfacePtr|.
bool is_bound() const { return static_cast<bool>(proxy_); }
// Whether this |SynchronousInterfacePtr| is currently bound to a channel.
//
// See |is_bound| for details.
explicit operator bool() const { return is_bound(); }
// The |Interface| proxy associated with this |SynchronousInterfacePtr|.
//
// When this |SynchronousInterfacePtr| is bound, method calls on this
// |Interface| will be proxied to the remote endpoint of the connection.
// Methods that expect replies will block until the
// |SynchronousInterfacePtr| either receives a reply to that transaction.
//
// When this |SynchronousInterfacePtr| is not bound, this method returns
// nullptr.
//
// The returned |Interface| is thread-compatible and can be used from any
// thread.
InterfaceSync* get() const { return proxy_.get(); }
InterfaceSync* operator->() const { return get(); }
InterfaceSync& operator*() const { return *get(); }
// The underlying channel, or null channel if not currently bound.
zx::unowned_channel unowned_channel() const {
return proxy_ ? zx::unowned_channel(proxy_->proxy_.channel()) : zx::unowned_channel();
}
private:
std::unique_ptr<typename InterfaceSync::Proxy_> proxy_;
};
} // namespace fidl
#endif // LIB_FIDL_CPP_SYNCHRONOUS_INTERFACE_PTR_H_