template <typename Protocol>

class WireClient

Defined at line 111 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

|WireClient| is a client for sending and receiving FIDL wire messages, that

must be managed and used from a [synchronized async dispatcher][synchronized-dispatcher].

See |WireSharedClient| for a client that may be moved or cloned to different

dispatchers or arbitrary threads.

Generated FIDL APIs are accessed by 'dereferencing' the client value:

// Creates a client that speaks over |client_end|, on the |my_dispatcher| dispatcher.

fidl::WireClient client(std::move(client_end), my_dispatcher);

// Call the |Foo| method asynchronously, passing in a callback that will be

// invoked on a dispatcher thread when the server response arrives.

auto status = client->Foo(args, [] (Result result) {});

## Lifecycle

A client must be **bound** to an endpoint before it could be used. This

association between the endpoint and the client is called a "binding".

Binding a client to an endpoint starts the monitoring of incoming messages.

Those messages are appropriately dispatched: to response callbacks, to event

handlers, etc. FIDL methods (asynchronous or synchronous) may only be invoked

on a bound client.

Internally, a client is a lightweight reference to the binding, performing

its duties indirectly through that object, as illustrated by the simplified

diagram below:

references makes

client -------------> binding --------> FIDL call

This means that the client _object_ and the binding have overlapping but

slightly different lifetimes. For example, the binding may terminate in

response to fatal communication errors, leaving the client object alive but

unable to make any calls.

To stop the monitoring of incoming messages, one may **teardown** the

binding. When teardown is initiated, the client will not monitor new messages

on the endpoint. Ongoing callbacks will be allowed to run to completion. When

teardown is complete, further calls on the same client will fail. Unfulfilled

response callbacks will be dropped.

Destruction of a client object will initiate teardown.

Teardown will also be initiated when the binding encounters a terminal error:

- The server-end of the channel was closed.

- An epitaph was received.

- Decoding or encoding failed.

- An invalid or unknown message was encountered.

- Error waiting on, reading from, or writing to the channel.

In this case, the user will be notified of the detailed error via the

|on_fidl_error| method on the event handler.

## Thread safety

|WireClient| provides an easier to use API in exchange of a more restrictive

threading model:

- The provided |async_dispatcher_t| must be a [synchronized dispatcher][synchronized-dispatcher].

- The client must be bound on a task running on that dispatcher.

- The client must be destroyed on a task running on that dispatcher.

- FIDL method calls must be made from tasks running on that dispatcher.

- Responses are always delivered from dispatcher tasks, as are events.

The above rules are checked in debug builds at run-time. In short, the client

is local to its associated dispatcher.

Note that FIDL method calls must be synchronized with operations that consume

or mutate the |WireClient| itself:

- Assigning a new value to the |WireClient| variable.

- Moving the |WireClient| to a different location.

- Destroying the |WireClient|.

|WireClient| is suitable for systems with stronger sequential threading

guarantees. It is intended to be used as a local variable with fixed

lifetime, or as a member of a larger class where it is uniquely owned by

instances of that class. Destroying the |WireClient| is guaranteed to stop

message dispatch: since the client is destroyed on the dispatcher thread,

there is no opportunity of parallel callbacks to user code, and

use-after-free of user objects is naturally avoided during teardown.

See |WireSharedClient| for a client that supports binding and destroying on

arbitrary threads, at the expense of requiring two-phase shutdown.

[synchronized-dispatcher]:

https://fuchsia.dev/fuchsia-src/development/languages/c-cpp/thread-safe-async#synchronized-dispatcher

Public Methods

template <typename AsyncEventHandler = fidl::WireAsyncEventHandler<Protocol>>
void WireClient<Protocol> (fidl::internal::ClientEndType<Protocol> client_end, async_dispatcher_t * dispatcher, AsyncEventHandler * event_handler)

Create an initialized client which manages the binding of the client end of

a channel to a dispatcher, as if that client had been default-constructed

then later bound to that endpoint via |Bind|.

It is a logic error to use a dispatcher that is shutting down or already

shut down. Doing so will result in a panic.

If any other error occurs during initialization, the

|event_handler->on_fidl_error| handler will be invoked asynchronously with

the reason, if specified.

Defined at line 124 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

void WireClient<Protocol> ()

Create an uninitialized client. The client may then be bound to an endpoint

later via |Bind|.

Prefer using the constructor overload that binds the client to a channel

atomically during construction. Use this default constructor only when the

client must be constructed first before a channel could be obtained (for

example, if the client is an instance variable).

Defined at line 136 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

bool is_valid ()

Returns if the |WireClient| is initialized.

Defined at line 139 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

bool operator bool ()

Defined at line 140 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

void ~WireClient<Protocol> ()

The destructor of |WireClient| will initiate binding teardown.

When the client destructs:

- The channel will be closed.

- Pointers obtained via |get| will be invalidated.

- Binding teardown will happen, implying:

* In-progress calls will be forgotten. Async callbacks will be dropped.

Defined at line 149 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

void WireClient<Protocol> (WireClient<Protocol> && other)

|WireClient|s can be safely moved without affecting any in-flight FIDL

method calls. Note that calling methods on a client should be serialized

with respect to operations that consume the client, such as moving it or

destroying it.

Defined at line 155 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

WireClient<Protocol> & operator= (WireClient<Protocol> && other)

Defined at line 156 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

void Bind (fidl::internal::ClientEndType<Protocol> client_end, async_dispatcher_t * dispatcher, fidl::WireAsyncEventHandler<Protocol> * event_handler)

Initializes the client by binding the |client_end| endpoint to the

dispatcher.

It is a logic error to invoke |Bind| on a dispatcher that is shutting down

or already shut down. Doing so will result in a panic.

When other errors occur during binding, the |event_handler->on_fidl_error|

handler will be asynchronously invoked with the reason, if specified.

It is not allowed to call |Bind| on an initialized client. To rebind a

|WireClient| to a different endpoint, simply replace the |WireClient|

variable with a new instance.

Defined at line 170 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

auto operator-> ()

Returns the interface for making outgoing FIDL calls with managed memory

allocation. The client must be initialized first.

If the binding has been torn down, calls on the interface return error with

status |ZX_ERR_CANCELED| and reason |fidl::Reason::kUnbind|.

Persisting this pointer to a local variable is discouraged, since that

results in unsafe borrows. Always prefer making calls directly via the

|WireClient| reference-counting type.

Defined at line 187 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

template <typename MemoryResource>
auto buffer (MemoryResource && resource)

Returns a veneer object which exposes the caller-allocating API, using the

provided |resource| to allocate buffers necessary for each call. Requests

will live on those buffers. Responses on the other hand do not live on

those buffers; they are separately managed and may become invalid after the

corresponding async response/result callback returns.

Examples of supported memory resources are:

* |fidl::BufferSpan|, referencing a range of bytes.

* |fidl::AnyArena

&

|, referencing an arena.

* Any type for which there is a |MakeAnyBufferAllocator| specialization.

See |AnyBufferAllocator|.

This interface is suitable when one needs complete control over memory

allocation. Instead of implicitly heap allocating the necessary bookkeeping

for in-flight operations, the methods take a raw pointer to a

|fidl::WireResponseContext

<FidlMethod

>|, which may be allocated via any

means as long as it outlives the duration of this async FIDL call. Refer to

documentation on the response context.

The returned object borrows from this object, hence must not outlive

the client object.

The returned object may be briefly persisted for use over multiple calls:

fidl::Arena my_arena;

fidl::WireClient client(std::move(client_end), some_dispatcher);

auto buffered = client.buffer(my_arena);

buffered->FooMethod(args, foo_response_context);

buffered->BarMethod(args, bar_response_context);

...

In this situation, those calls will all use the initially provided memory

resource (`my_arena`) to allocate their message buffers. The memory

resource won't be reset/overwritten across calls. Note that if a

|BufferSpan| is provided as the memory resource, sharing memory resource in

this manner may eventually exhaust the capacity of the buffer span since it

represents a single fixed size buffer. To reuse (overwrite) the underlying

buffer across multiple calls, obtain a new caller-allocating veneer object

for each call:

fidl::BufferSpan span(some_large_buffer, size);

fidl::WireClient client(std::move(client_end), some_dispatcher);

client.buffer(span)->FooMethod(args, foo_response_context);

client.buffer(span)->BarMethod(args, bar_response_context);

Defined at line 238 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

auto sync ()

Returns a veneer object exposing synchronous calls. Example:

fidl::WireClient client(std::move(client_end), some_dispatcher);

fidl::WireResult result = client.sync()->FooMethod(args);

Defined at line 249 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

fit::result<fidl::Error, fidl::ClientEnd<Protocol>> UnbindMaybeGetEndpoint ()

Attempts to disassociate the client object from its endpoint and stop

monitoring it for messages. After this call, subsequent operations will

fail with an unbound error.

If there are pending two-way async calls, the endpoint is closed and this

method will fail with |fidl::Reason::kPendingTwoWayCallPreventsUnbind|. The

caller needs to arrange things such that unbinding happens after any

replies to two-way calls.

If the endpoint was already closed due to an earlier error, that error will

be returned here.

Otherwise, returns the client endpoint.

Defined at line 267 of file ../../sdk/lib/fidl/cpp/wire/include/lib/fidl/cpp/wire/client.h

Friends

template <typename Protocol>
class ClientChecker