blob: 7db775a9b7ca2eb8f3734a12e50bd543246e06e6 [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_REQUEST_H_
#define LIB_FIDL_CPP_INTERFACE_REQUEST_H_
#include <lib/fidl/epitaph.h>
#include <lib/fit/function.h>
#include <lib/zx/channel.h>
#include <cstddef>
#include <utility>
#include "lib/fidl/cpp/clone.h"
#include "lib/fidl/cpp/coding_traits.h"
namespace fidl {
class Builder;
// The server 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
// |InterfaceHandle|.
//
// An |InterfaceRequest| does not have thread affinity and can therefore be
// transferred to another thread or another process. To bind an implementation
// of |Interface| to this |InterfaceRequest|, use a |Binding| object.
//
// Typically, |InterfaceRequest| objects are created by a prospective client of
// |Interface|, which then sends the |InterfaceRequest| to another process to
// request that the remote process implement the |Interface|. This pattern
// enables *pipelined* operation, in which the client can start calling methods
// on an associated |InterfacePtr| immediately, before the |InterfaceRequest|
// has reached the remote process and been bound to an implementation. These
// method calls are buffered by the underlying channel until they are read by
// the remote process.
//
// Example:
//
// #include "foo.fidl.h"
//
// class FooImpl : public Foo {
// public:
// explicit FooImpl(InterfaceRequest<Foo> request)
// : binding_(this, std::move(request)) {}
//
// // Foo implementation here.
//
// private:
// Binding<Foo> binding_;
// };
//
// After the |InterfaceRequest| has been bound to an implementation, the
// implementation will receive method calls from the remote endpoint of the
// channel on the thread to which the |InterfaceRequest| was bound.
//
// See also:
//
// * |InterfaceHandle|, which is the client analog of an |InterfaceRequest|.
template <typename Interface>
class InterfaceRequest final {
public:
// Creates an |InterfaceHandle| whose underlying channel is invalid.
//
// Some protocols contain messages that permit such |InterfaceRequest|
// objects, which indicate that the client is not interested in the server
// providing an implementation of |Interface|.
InterfaceRequest() = default;
// Creates an |InterfaceHandle| that wraps the given |channel|.
explicit InterfaceRequest(zx::channel channel) : channel_(std::move(channel)) {}
InterfaceRequest(const InterfaceRequest& other) = delete;
InterfaceRequest& operator=(const InterfaceRequest& other) = delete;
InterfaceRequest(InterfaceRequest&& other) : channel_(std::move(other.channel_)) {}
InterfaceRequest& operator=(InterfaceRequest&& other) {
channel_ = std::move(other.channel_);
return *this;
}
// Implicit conversion from nullptr to an |InterfaceRequest| with an
// invalid |channel|.
InterfaceRequest(std::nullptr_t) {}
// 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, InterfaceRequest<Interface>* value, size_t offset) {
decoder->DecodeHandle(&value->channel_, offset);
}
// Sends an Epitaph over the bound channel corresponding to the error passed
// as a parameter, closes the channel, and unbinds it. An Epitaph is the last
// message sent over a channel before a close operation; for the purposes of
// this function, it can be thought of as a return code. See the FIDL
// language spec for more information about Epitaphs.
//
// The return value can be any of the return values of zx_channel_write.
zx_status_t Close(zx_status_t epitaph_value) {
return is_valid() ? fidl_epitaph_write(TakeChannel().get(), epitaph_value) : ZX_ERR_BAD_STATE;
}
private:
zx::channel channel_;
};
// A |InterfaceRequestHandler<Interface>| is simply a function that
// handles an interface request for |Interface|. If it determines that the
// request should be "accepted", then it should "connect" ("take ownership
// of") request. Otherwise, it can simply drop |request| (as implied by the
// interface).
template <typename Interface>
using InterfaceRequestHandler = fit::function<void(fidl::InterfaceRequest<Interface> request)>;
// Equality.
template <typename T>
struct Equality<InterfaceRequest<T>> {
bool operator()(const InterfaceRequest<T>& lhs, const InterfaceRequest<T>& rhs) const {
return lhs.channel() == rhs.channel();
}
};
template <typename T>
struct CodingTraits<InterfaceRequest<T>>
: public EncodableCodingTraits<InterfaceRequest<T>, sizeof(zx_handle_t)> {};
template <typename T>
inline zx_status_t Clone(const InterfaceRequest<T>& value, InterfaceRequest<T>* result) {
if (!value) {
*result = InterfaceRequest<T>();
return ZX_OK;
}
return ZX_ERR_ACCESS_DENIED;
}
} // namespace fidl
#endif // LIB_FIDL_CPP_INTERFACE_REQUEST_H_