blob: f33ffe12c25907e82df001a53a7bd1df2be03eb3 [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_INTERFACE_HANDLE_H_
#define LIB_FIDL_CPP_INTERFACE_HANDLE_H_
#include <lib/zx/channel.h>
#include <zircon/assert.h>
#include <cstddef>
#include <utility>
#include "lib/fidl/cpp/clone.h"
#include "lib/fidl/cpp/coding_traits.h"
#include "lib/fidl/cpp/interface_request.h"
namespace fidl {
class Builder;
template <typename Interface>
class InterfacePtr;
template <typename Interface>
class SynchronousInterfacePtr;
// The client endpoint of a FIDL channel.
//
// The remote end of the channel expects this end of the channel to speak the
// protocol associated with |Interface|. This type is the dual of
// |InterfaceRequest|.
//
// Unlike an |InterfacePtr|, an |InterfaceHandle| does not have thread affinity
// and can therefore be transferred to another thread or another process. To
// create an |InterfacePtr| to send messages on this channel, call the |Bind()|
// method, either on the |InterfaceHandle| or the |InterfacePtr| object.
//
// See also:
//
// * |InterfaceRequest|, which is the server analog of an |InterfaceHandle|.
template <typename Interface>
class InterfaceHandle final {
public:
// Creates an |InterfaceHandle| whose underlying channel is invalid.
InterfaceHandle() = default;
// Creates an |InterfaceHandle| that wraps the given |channel|.
explicit InterfaceHandle(zx::channel channel) : channel_(std::move(channel)) {}
InterfaceHandle(const InterfaceHandle& other) = delete;
InterfaceHandle& operator=(const InterfaceHandle& other) = delete;
InterfaceHandle(InterfaceHandle&& other) : channel_(std::move(other.channel_)) {}
InterfaceHandle& operator=(InterfaceHandle&& other) {
channel_ = std::move(other.channel_);
return *this;
}
// Implicit conversion from nullptr to an |InterfaceHandle| without a valid
// |channel|.
InterfaceHandle(std::nullptr_t) {}
// Implicit conversion from |InterfacePtr| unbinds the channel from the
// |InterfacePtr|.
//
// This requires the caller to provide an rvalue reference, as the caller's
// InterfacePtr is effectively moved out of.
//
// Making this constructor templated ensures that it is not type-instantiated
// unless it is used, making the InterfacePtr<->InterfaceHandle codependency
// less fragile.
//
// The std::enable_if_t avoids creation of unintended implicit type
// conversions (especially from anything else that has an "Unbind()"),
// presumably due to InterfacePtrType being inferred to be something other
// than InterfacePtr<Interface>. However, if a caller is trying to use a type
// that's only incorrect due to not being an rvalue reference, we do permit
// this constructor to be selected, but then static_assert() with a message
// suggesting std::move().
template <typename InterfacePtrType = InterfacePtr<Interface>,
typename std::enable_if_t<
std::is_same<InterfacePtr<Interface>,
typename std::remove_reference<InterfacePtrType>::type>::value ||
std::is_same<SynchronousInterfacePtr<Interface>,
typename std::remove_reference<InterfacePtrType>::type>::value,
int>
zero_not_used = 0>
InterfaceHandle(InterfacePtrType&& ptr) {
static_assert(std::is_same<InterfacePtr<Interface>&&, decltype(ptr)>::value ||
std::is_same<SynchronousInterfacePtr<Interface>&&, decltype(ptr)>::value,
"Implicit conversion from InterfacePtr<> (or "
"SynchronousInterfacePtr<>) to InterfaceHandle<> requires an rvalue "
"reference. Maybe there's a missing std::move(), or consider "
"using/providing an InterfaceHandle<> directly instead (particularly "
"if the usage prior to this conversion doesn't need to send or receive "
"messages).");
*this = ptr.Unbind();
}
// Creates a new channel, retains one endpoint in this |InterfaceHandle| and
// returns the other as an |InterfaceRequest|.
//
// Typically, the returned |InterfaceRequest| is passed to another process,
// which will implement the server endpoint for the |Interface| protocol.
//
// If |NewRequest| fails to create the underlying channel, the returned
// |InterfaceRequest| will return false from |is_valid()|.
InterfaceRequest<Interface> NewRequest() {
zx::channel h1, h2;
if (zx::channel::create(0, &h1, &h2) != ZX_OK)
return nullptr;
channel_ = std::move(h1);
return InterfaceRequest<Interface>(std::move(h2));
}
// Creates an |InterfacePtr| bound to the channel in this |InterfaceHandle|.
//
// This function transfers ownership of the underlying channel to the
// returned |InterfacePtr|, which means the |is_valid()| method will return
// false after this method returns.
//
// Requires the current thread to have a default async_dispatcher_t (e.g., a
// message loop) in order to read messages from the channel and to monitor the
// channel for |ZX_CHANNEL_PEER_CLOSED|.
//
// Making this method templated ensures that it is not type-instantiated
// unless it is used, making the InterfacePtr<->InterfaceHandle codependency
// less fragile.
template <typename InterfacePtr = InterfacePtr<Interface>>
inline InterfacePtr Bind() {
InterfacePtr ptr;
ptr.Bind(std::move(channel_));
return ptr;
}
template <typename SyncInterfacePtr = SynchronousInterfacePtr<Interface>>
inline SyncInterfacePtr BindSync() {
SyncInterfacePtr ptr;
ptr.Bind(std::move(channel_));
return ptr;
}
// Whether the underlying channel is valid.
bool is_valid() const { return !!channel_; }
explicit operator bool() const { return is_valid(); }
// Transfers ownership of the underlying channel to the caller.
zx::channel TakeChannel() { return std::move(channel_); }
// The underlying channel.
const zx::channel& channel() const { return channel_; }
void set_channel(zx::channel channel) { channel_ = std::move(channel); }
void Encode(Encoder* encoder, size_t offset) { encoder->EncodeHandle(&channel_, offset); }
static void Decode(Decoder* decoder, InterfaceHandle<Interface>* value, size_t offset) {
decoder->DecodeHandle(&value->channel_, offset);
}
private:
zx::channel channel_;
};
// Equality.
template <typename T>
struct Equality<InterfaceHandle<T>> {
bool operator()(const InterfaceHandle<T>& lhs, const InterfaceHandle<T>& rhs) const {
return lhs.channel() == rhs.channel();
}
};
template <typename T>
struct CodingTraits<InterfaceHandle<T>>
: public EncodableCodingTraits<InterfaceHandle<T>, sizeof(zx_handle_t)> {};
template <typename T>
inline zx_status_t Clone(const InterfaceHandle<T>& value, InterfaceHandle<T>* result) {
if (!value) {
*result = InterfaceHandle<T>();
return ZX_OK;
}
return ZX_ERR_ACCESS_DENIED;
}
} // namespace fidl
#endif // LIB_FIDL_CPP_INTERFACE_HANDLE_H_