blob: 66a1e99b7b3672243229f250a9fb6ab152f9222d [file] [log] [blame]
// Copyright 2022 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.
// channel.h is the "entrypoint header" that should be included when using the
// channel transport with the unified bindings.
#ifndef SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_CHANNEL_H_
#define SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_CHANNEL_H_
#include <lib/fidl/cpp/client.h>
#include <lib/fidl/cpp/unified_messaging.h>
#include <lib/fidl/llcpp/channel.h>
#include <lib/fidl/llcpp/internal/arrow.h>
#include <lib/fidl/llcpp/internal/transport_channel.h>
#include <lib/fidl/llcpp/server.h>
namespace fidl {
//
// Note: when updating the documentation below, please make similar updates to
// the one in //zircon/system/ulib/fidl/include/lib/fidl/llcpp/channel.h
//
// The interface documentation on |fidl::SyncClient| is largely identical to
// those on |fidl::WireSyncClient|, after removing the "wire" portion from
// comments.
//
// |fidl::SyncClient| owns a client endpoint and exposes synchronous FIDL calls
// taking both natural and wire types. Prefer using this owning class over
// |fidl::Call| unless one has to interface with very low-level functionality
// (such as making a call over a raw zx_handle_t).
//
// Generated FIDL APIs are accessed by 'dereferencing' the client value:
//
// // Creates a sync client that speaks over |client_end|.
// fidl::SyncClient client(std::move(client_end));
//
// // Call the |Foo| method synchronously, obtaining the results from the
// // return value.
// fidl::Result result = client->Foo(args);
//
// |fidl::SyncClient| is suitable for code without access to an async
// dispatcher.
//
// |fidl::SyncClient| includes a superset of the functionality of
// |fidl::WireSyncClient|, which only exposes synchronous FIDL calls with wire
// types. Prefer |fidl::SyncClient| over |fidl::WireSyncClient| unless your
// application needs to statically enforce that only the more performant wire
// types are used.
//
// ## Thread safety
//
// |SyncClient| is generally thread-safe with a few caveats:
//
// - Client objects can be safely sent between threads.
// - One may invoke many FIDL methods in parallel on the same client. However,
// FIDL method calls must be synchronized with operations that consume or
// mutate the client object itself:
//
// - Calling `Bind` or `TakeClientEnd`.
// - Assigning a new value to the |SyncClient| variable.
// - Moving the |SyncClient| to a different location.
// - Destroying the |SyncClient|.
//
// - There can be at most one `HandleOneEvent` call going on at the same time.
template <typename FidlProtocol>
class SyncClient : private WireSyncClient<FidlProtocol> {
private:
using Base = WireSyncClient<FidlProtocol>;
public:
// Creates an uninitialized client that is not bound to a client endpoint.
//
// Prefer using the constructor overload that initializes the client
// atomically during construction. Use this default constructor only when the
// client must be constructed first before an endpoint could be obtained (for
// example, if the client is an instance variable).
//
// The client may be initialized later via |Bind|.
SyncClient() = default;
// Creates an initialized client. FIDL calls will be made on |client_end|.
//
// Similar to |fidl::Client|, the client endpoint must be valid.
//
// To just make a FIDL call uniformly on a client endpoint that may or may not
// be valid, use the |fidl::Call(client_end)| helper. We may extend
// |fidl::SyncClient<P>| with richer features hinging on having a valid
// endpoint in the future.
explicit SyncClient(::fidl::ClientEnd<FidlProtocol> client_end) : Base(std::move(client_end)) {}
~SyncClient() = default;
SyncClient(SyncClient&&) noexcept = default;
SyncClient& operator=(SyncClient&&) noexcept = default;
// Whether the client is initialized.
bool is_valid() const { return Base::is_valid(); }
explicit operator bool() const { return Base::operator bool(); }
// Borrows the underlying client endpoint. The client must have been
// initialized.
const ::fidl::ClientEnd<FidlProtocol>& client_end() const { return Base::client_end(); }
// Initializes the client with a |client_end|. FIDL calls will be made on this
// endpoint.
//
// It is not allowed to call |Bind| on an initialized client. To rebind a
// |SyncClient| to a different endpoint, simply replace the
// |SyncClient| variable with a new instance.
void Bind(::fidl::ClientEnd<FidlProtocol> client_end) { Base::Bind(std::move(client_end)); }
// Extracts the underlying endpoint from the client. After this operation, the
// client goes back to an uninitialized state.
//
// It is not safe to invoke this method while there are ongoing FIDL calls.
::fidl::ClientEnd<FidlProtocol> TakeClientEnd() { return Base::TakeClientEnd(); }
// Returns the interface for making FIDL calls with natural objects.
internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>> operator->()
const {
ZX_ASSERT(is_valid());
return internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>>(
fidl::internal::MakeAnyUnownedTransport(client_end().handle()));
}
// Returns the interface for making outgoing FIDL calls using wire objects.
// The client must be initialized first.
const Base& wire() const { return *this; }
// TODO(fxbug.dev/60240): Implement natural sync event handler.
//
// Handle all possible events defined in this protocol.
//
// Blocks to consume exactly one message from the channel, then call the corresponding virtual
// method defined in |event_handler|. If the message was unknown or malformed, returns an
// error without calling any virtual method.
::fidl::Status HandleOneEvent(fidl::WireSyncEventHandler<FidlProtocol>& event_handler) const {
return event_handler.HandleOneEvent(client_end());
}
};
template <typename FidlProtocol>
SyncClient(fidl::ClientEnd<FidlProtocol>) -> SyncClient<FidlProtocol>;
// |Call| is used to make method calls directly on a |fidl::ClientEnd|
// without having to set up a client. Call it like:
//
// fidl::Call(client_end)->Method(args...);
//
template <typename FidlProtocol>
internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>> Call(
const fidl::ClientEnd<FidlProtocol>& client_end) {
return internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>>(
fidl::internal::MakeAnyUnownedTransport(client_end.borrow().handle()));
}
// |Call| is used to make method calls directly on a |fidl::ClientEnd|
// without having to set up a client. Call it like:
//
// fidl::Call(client_end)->Method(args...);
//
template <typename FidlProtocol>
internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>> Call(
const fidl::UnownedClientEnd<FidlProtocol>& client_end) {
return internal::SyncEndpointManagedVeneer<internal::NaturalSyncClientImpl<FidlProtocol>>(
fidl::internal::MakeAnyUnownedTransport(client_end.handle()));
}
// Return an interface for sending FIDL events containing natural domain objects
// over the endpoint managed by |binding_ref|. Call it like:
//
// fidl::SendEvent(server_binding_ref)->FooEvent(event_body);
//
template <typename FidlProtocol>
auto SendEvent(const ServerBindingRef<FidlProtocol>& binding_ref) {
return internal::Arrow<internal::NaturalWeakEventSender<FidlProtocol>>(internal::BorrowBinding(
static_cast<const fidl::internal::ServerBindingRefBase&>(binding_ref)));
}
// Return an interface for sending FIDL events containing natural domain objects
// over |server_end|. Call it like:
//
// fidl::SendEvent(server_end)->FooEvent(event_body);
//
template <typename FidlProtocol>
auto SendEvent(const ServerEnd<FidlProtocol>& server_end) {
return internal::Arrow<internal::NaturalEventSender<FidlProtocol>>(
fidl::internal::MakeAnyUnownedTransport(server_end.channel()));
}
} // namespace fidl
#endif // SRC_LIB_FIDL_CPP_INCLUDE_LIB_FIDL_CPP_CHANNEL_H_