fidl_next_bind/
client.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use core::future::Future;
6use core::marker::PhantomData;
7use core::ops::Deref;
8
9use fidl_next_protocol::{self as protocol, ClientHandler, IgnoreEvents, ProtocolError, Transport};
10
11use crate::{ClientEnd, Protocol};
12
13/// A strongly typed client.
14#[repr(transparent)]
15pub struct Client<
16    P,
17    #[cfg(feature = "fuchsia")] T: Transport = zx::Channel,
18    #[cfg(not(feature = "fuchsia"))] T: Transport,
19> {
20    client: protocol::Client<T>,
21    _protocol: PhantomData<P>,
22}
23
24unsafe impl<P, T> Send for Client<P, T>
25where
26    T: Transport,
27    protocol::Client<T>: Send,
28{
29}
30
31impl<P, T: Transport> Client<P, T> {
32    /// Creates a new client handle from an untyped client handle.
33    pub fn from_untyped(client: protocol::Client<T>) -> Self {
34        Self { client, _protocol: PhantomData }
35    }
36
37    /// Closes the channel from the client end.
38    pub fn close(&self) {
39        self.client.close();
40    }
41}
42
43impl<P, T: Transport> Clone for Client<P, T> {
44    fn clone(&self) -> Self {
45        Self { client: self.client.clone(), _protocol: PhantomData }
46    }
47}
48
49impl<P: Protocol<T>, T: Transport> Deref for Client<P, T> {
50    type Target = P::Client;
51
52    fn deref(&self) -> &Self::Target {
53        // SAFETY: `P::Client` is a `#[repr(transparent)]` wrapper around
54        // `Client<T>`.
55        unsafe { &*(self as *const Self).cast::<P::Client>() }
56    }
57}
58
59/// A protocol which dispatches incoming client messages to a handler.
60pub trait DispatchClientMessage<
61    H,
62    #[cfg(feature = "fuchsia")] T: Transport = zx::Channel,
63    #[cfg(not(feature = "fuchsia"))] T: Transport,
64>: Sized + 'static
65{
66    /// Handles a received client event with the given handler.
67    fn on_event(
68        handler: &mut H,
69        ordinal: u64,
70        buffer: T::RecvBuffer,
71    ) -> impl Future<Output = Result<(), ProtocolError<T::Error>>> + Send;
72}
73
74/// An adapter for a client protocol handler.
75pub struct ClientHandlerAdapter<P, H> {
76    handler: H,
77    _protocol: PhantomData<P>,
78}
79
80unsafe impl<P, H> Send for ClientHandlerAdapter<P, H> where H: Send {}
81
82impl<P, H> ClientHandlerAdapter<P, H> {
83    /// Creates a new protocol client handler from a supported handler.
84    pub fn from_untyped(handler: H) -> Self {
85        Self { handler, _protocol: PhantomData }
86    }
87}
88
89impl<P, H, T> ClientHandler<T> for ClientHandlerAdapter<P, H>
90where
91    P: DispatchClientMessage<H, T>,
92    T: Transport,
93{
94    fn on_event(
95        &mut self,
96        ordinal: u64,
97        buffer: T::RecvBuffer,
98    ) -> impl Future<Output = Result<(), ProtocolError<T::Error>>> + Send {
99        P::on_event(&mut self.handler, ordinal, buffer)
100    }
101}
102
103/// A strongly typed client dispatcher.
104pub struct ClientDispatcher<
105    P,
106    #[cfg(feature = "fuchsia")] T: Transport = zx::Channel,
107    #[cfg(not(feature = "fuchsia"))] T: Transport,
108> {
109    dispatcher: protocol::ClientDispatcher<T>,
110    _protocol: PhantomData<P>,
111}
112
113unsafe impl<P, T> Send for ClientDispatcher<P, T>
114where
115    T: Transport,
116    protocol::Client<T>: Send,
117{
118}
119
120impl<P, T: Transport> ClientDispatcher<P, T> {
121    /// Creates a new client from a client end.
122    pub fn new(client_end: ClientEnd<P, T>) -> Self {
123        Self {
124            dispatcher: protocol::ClientDispatcher::new(client_end.into_untyped()),
125            _protocol: PhantomData,
126        }
127    }
128
129    /// Returns the dispatcher's client.
130    pub fn client(&self) -> Client<P, T> {
131        Client::from_untyped(self.dispatcher.client())
132    }
133
134    /// Creates a new client from an untyped client.
135    pub fn from_untyped(dispatcher: protocol::ClientDispatcher<T>) -> Self {
136        Self { dispatcher, _protocol: PhantomData }
137    }
138
139    /// Runs the client with the provided handler.
140    pub async fn run<H>(self, handler: H) -> Result<H, ProtocolError<T::Error>>
141    where
142        P: DispatchClientMessage<H, T>,
143    {
144        self.dispatcher
145            .run(ClientHandlerAdapter { handler, _protocol: PhantomData::<P> })
146            .await
147            .map(|adapter| adapter.handler)
148    }
149
150    /// Runs the client, ignoring any incoming events.
151    pub async fn run_client(self) -> Result<(), ProtocolError<T::Error>> {
152        self.dispatcher.run(IgnoreEvents).await.map(|_| ())
153    }
154}