| // Copyright 2020 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_LLCPP_CLIENT_END_H_ |
| #define LIB_FIDL_LLCPP_CLIENT_END_H_ |
| |
| #include <lib/fidl/epitaph.h> |
| #include <lib/fidl/llcpp/soft_migration.h> |
| #include <lib/zx/channel.h> |
| #include <zircon/assert.h> |
| |
| namespace fidl { |
| |
| template <typename Protocol> |
| class UnownedClientEnd; |
| |
| // The client endpoint of a FIDL channel. |
| // |
| // The remote (server) counterpart of the channel expects this end of the |
| // channel to speak the protocol represented by |Protocol|. This type is the |
| // dual of |ServerEnd|. |
| // |
| // |ClientEnd| is thread-compatible: it may be transferred to another thread |
| // or another process. |
| template <typename Protocol> |
| class ClientEnd final { |
| public: |
| using ProtocolType = Protocol; |
| |
| // Creates a |ClientEnd| whose underlying channel is invalid. |
| // |
| // Both optional and non-optional client endpoints in FIDL declarations map |
| // to this same type. If this ClientEnd is passed to a method or FIDL |
| // protocol that requires valid channels, those operations will fail at |
| // run-time. |
| ClientEnd() = default; |
| |
| // Creates an |ClientEnd| that wraps the given |channel|. |
| // The caller must ensure the |channel| is a client endpoint speaking |
| // a protocol compatible with |Protocol|. |
| // |
| // TODO(fxbug.dev/65212): Make the conversion explicit as users migrate to |
| // typed channels. |
| // NOLINTNEXTLINE |
| FIDL_CONDITIONALLY_EXPLICIT_CONVERSION ClientEnd(zx::channel channel) |
| : channel_(std::move(channel)) {} |
| |
| ClientEnd(ClientEnd&& other) noexcept = default; |
| ClientEnd& operator=(ClientEnd&& other) noexcept = default; |
| |
| // Whether the underlying channel is valid. |
| bool is_valid() const { return channel_.is_valid(); } |
| explicit operator bool() const { return is_valid(); } |
| |
| // Close the underlying channel if any, |
| // and reset the object back to an invalid state. |
| void reset() { channel_.reset(); } |
| |
| // The underlying channel. |
| const zx::channel& channel() const { return channel_; } |
| zx::channel& channel() { return channel_; } |
| |
| // Transfers ownership of the underlying channel to the caller. |
| zx::channel TakeChannel() { return std::move(channel_); } |
| |
| // Returns a type-safe copy of the underlying channel in this |ClientEnd| |
| // that does not claim ownership. |
| fidl::UnownedClientEnd<Protocol> borrow() const { |
| return UnownedClientEnd<Protocol>(channel_.borrow()); |
| } |
| |
| private: |
| zx::channel channel_; |
| }; |
| |
| // A typed client endpoint that does not claim ownership. It is typically |
| // created from an owning |fidl::ClientEnd<Protocol>|. |
| // These types are used by generated FIDL APIs that do not take ownership. |
| // |
| // The remote (server) counterpart of the channel expects this end of the |
| // channel to speak the protocol represented by |Protocol|. |
| // |
| // Compared to a |const fidl::ClientEnd<Protocol>&|, |
| // |fidl::UnownedClientEnd<Protocol>| has the additional flexibility of being |
| // able to be stored in a member variable or field, while still remembering |
| // the associated FIDL protocol. |
| template <typename Protocol> |
| class UnownedClientEnd final { |
| public: |
| using ProtocolType = Protocol; |
| |
| // An unowned client end can only be constructed from an existing channel. |
| // |
| // This constructor defines an implicit conversion to facilitate invoking |
| // generated FIDL APIs with either an unowned client end, or a const |
| // reference to a |fidl::ClientEnd<Protocol>|. |
| // NOLINTNEXTLINE |
| UnownedClientEnd(const ClientEnd<Protocol>& owner) : UnownedClientEnd(owner.channel().get()) {} |
| |
| // Creates an |UnownedClientEnd| from a raw zircon handle. |
| // Prefer only using this constructor when interfacing with C APIs. |
| constexpr explicit UnownedClientEnd(zx_handle_t h) : channel_(h) {} |
| |
| // Creates an |UnownedClientEnd| from a |zx::unowned_channel|. |
| // |
| // Using this constructor is discouraged since it tends to erase the actual |
| // type of the underlying protocol. |
| // Consider declaring the type of the input variable as a |
| // |fidl::UnownedClientEnd<Protocol>| instead. |
| // |
| // TODO(fxbug.dev/65212): Make the conversion explicit as users migrate to |
| // typed channels. |
| // NOLINTNEXTLINE |
| FIDL_CONDITIONALLY_EXPLICIT_CONVERSION UnownedClientEnd(const zx::unowned_channel& h) |
| : channel_(h->get()) {} |
| |
| // The unowned client end is copyable - it simply copies the handle value. |
| UnownedClientEnd(const UnownedClientEnd& other) = default; |
| UnownedClientEnd& operator=(const UnownedClientEnd& other) = default; |
| |
| // Whether the underlying channel is valid. |
| bool is_valid() const { return channel_ != ZX_HANDLE_INVALID; } |
| explicit operator bool() const { return is_valid(); } |
| |
| // The underlying channel. |
| zx::unowned_channel channel() const { return zx::unowned_channel(channel_); } |
| |
| // The underlying channel, as a |zx_handle_t|. |
| zx_handle_t handle() const { return channel_; } |
| |
| private: |
| zx_handle_t channel_; |
| }; |
| |
| // Comparison operators between client-end objects. |
| // These comparisons have the same semantics as the comparison operators |
| // on the wrapped |zx::channel|s. |
| |
| template <typename T> |
| bool operator==(const ClientEnd<T>& a, const ClientEnd<T>& b) { |
| return a.channel() == b.channel(); |
| } |
| |
| template <typename T> |
| bool operator!=(const ClientEnd<T>& a, const ClientEnd<T>& b) { |
| return !(a == b); |
| } |
| |
| template <typename T> |
| bool operator<(const ClientEnd<T>& a, const ClientEnd<T>& b) { |
| return a.channel() < b.channel(); |
| } |
| |
| template <typename T> |
| bool operator>(const ClientEnd<T>& a, const ClientEnd<T>& b) { |
| return a.channel() > b.channel(); |
| } |
| |
| template <typename T> |
| bool operator<=(const ClientEnd<T>& a, const ClientEnd<T>& b) { |
| return a.channel() <= b.channel(); |
| } |
| |
| template <typename T> |
| bool operator>=(const ClientEnd<T>& a, const ClientEnd<T>& b) { |
| return a.channel() >= b.channel(); |
| } |
| |
| template <typename T> |
| bool operator==(const UnownedClientEnd<T>& a, const UnownedClientEnd<T>& b) { |
| return a.channel() == b.channel(); |
| } |
| |
| template <typename T> |
| bool operator!=(const UnownedClientEnd<T>& a, const UnownedClientEnd<T>& b) { |
| return !(a == b); |
| } |
| |
| template <typename T> |
| bool operator<(const UnownedClientEnd<T>& a, const UnownedClientEnd<T>& b) { |
| return a.channel() < b.channel(); |
| } |
| |
| template <typename T> |
| bool operator>(const UnownedClientEnd<T>& a, const UnownedClientEnd<T>& b) { |
| return a.channel() > b.channel(); |
| } |
| |
| template <typename T> |
| bool operator<=(const UnownedClientEnd<T>& a, const UnownedClientEnd<T>& b) { |
| return a.channel() <= b.channel(); |
| } |
| |
| template <typename T> |
| bool operator>=(const UnownedClientEnd<T>& a, const UnownedClientEnd<T>& b) { |
| return a.channel() >= b.channel(); |
| } |
| |
| } // namespace fidl |
| |
| #endif // LIB_FIDL_LLCPP_CLIENT_END_H_ |