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;
8use core::pin::Pin;
9use core::task::{Context, Poll};
10
11use fidl_next_codec::{Decode, DecoderExt as _};
12use fidl_next_protocol::{self as protocol, IgnoreEvents, ProtocolError, Transport};
13
14use crate::{ClientEnd, Error, Method, Protocol, Response};
15
16/// A strongly typed client sender.
17#[repr(transparent)]
18pub struct ClientSender<
19    P,
20    #[cfg(feature = "fuchsia")] T: Transport = zx::Channel,
21    #[cfg(not(feature = "fuchsia"))] T: Transport,
22> {
23    sender: protocol::ClientSender<T>,
24    _protocol: PhantomData<P>,
25}
26
27unsafe impl<P, T> Send for ClientSender<P, T>
28where
29    T: Transport,
30    protocol::ClientSender<T>: Send,
31{
32}
33
34impl<P, T: Transport> ClientSender<P, T> {
35    /// Wraps an untyped sender reference, returning a typed sender reference.
36    pub fn wrap_untyped(client: &protocol::ClientSender<T>) -> &Self {
37        unsafe { &*(client as *const protocol::ClientSender<T>).cast() }
38    }
39
40    /// Closes the channel from the client end.
41    pub fn close(&self) {
42        self.sender.close();
43    }
44}
45
46impl<P, T: Transport> Clone for ClientSender<P, T> {
47    fn clone(&self) -> Self {
48        Self { sender: self.sender.clone(), _protocol: PhantomData }
49    }
50}
51
52impl<P: Protocol<T>, T: Transport> Deref for ClientSender<P, T> {
53    type Target = P::ClientSender;
54
55    fn deref(&self) -> &Self::Target {
56        // SAFETY: `P::ClientSender` is a `#[repr(transparent)]` wrapper around `ClientSender<T>`.
57        unsafe { &*(self as *const Self).cast::<P::ClientSender>() }
58    }
59}
60
61/// A protocol which supports clients.
62pub trait ClientProtocol<
63    H,
64    #[cfg(feature = "fuchsia")] T: Transport = zx::Channel,
65    #[cfg(not(feature = "fuchsia"))] T: Transport,
66>: Sized + 'static
67{
68    /// Handles a received client event with the given handler.
69    fn on_event(
70        handler: &mut H,
71        sender: &ClientSender<Self, T>,
72        ordinal: u64,
73        buffer: T::RecvBuffer,
74    ) -> impl Future<Output = ()> + Send;
75}
76
77/// An adapter for a client protocol handler.
78pub struct ClientAdapter<P, H> {
79    handler: H,
80    _protocol: PhantomData<P>,
81}
82
83unsafe impl<P, H> Send for ClientAdapter<P, H> where H: Send {}
84
85impl<P, H> ClientAdapter<P, H> {
86    /// Creates a new protocol client handler from a supported handler.
87    pub fn from_untyped(handler: H) -> Self {
88        Self { handler, _protocol: PhantomData }
89    }
90}
91
92impl<P, H, T> protocol::ClientHandler<T> for ClientAdapter<P, H>
93where
94    P: ClientProtocol<H, T>,
95    T: Transport,
96{
97    fn on_event(
98        &mut self,
99        sender: &protocol::ClientSender<T>,
100        ordinal: u64,
101        buffer: T::RecvBuffer,
102    ) -> impl Future<Output = ()> + Send {
103        P::on_event(&mut self.handler, ClientSender::wrap_untyped(sender), ordinal, buffer)
104    }
105}
106
107/// A strongly typed client.
108pub struct Client<
109    P,
110    #[cfg(feature = "fuchsia")] T: Transport = zx::Channel,
111    #[cfg(not(feature = "fuchsia"))] T: Transport,
112> {
113    client: protocol::Client<T>,
114    _protocol: PhantomData<P>,
115}
116
117unsafe impl<P, T> Send for Client<P, T>
118where
119    T: Transport,
120    protocol::Client<T>: Send,
121{
122}
123
124impl<P, T: Transport> Client<P, T> {
125    /// Creates a new client from a client end.
126    pub fn new(client_end: ClientEnd<P, T>) -> Self {
127        Self { client: protocol::Client::new(client_end.into_untyped()), _protocol: PhantomData }
128    }
129
130    /// Returns the sender for the client.
131    pub fn sender(&self) -> &ClientSender<P, T> {
132        ClientSender::wrap_untyped(self.client.sender())
133    }
134
135    /// Creates a new client from an untyped client.
136    pub fn from_untyped(client: protocol::Client<T>) -> Self {
137        Self { client, _protocol: PhantomData }
138    }
139
140    /// Runs the client with the provided handler.
141    pub async fn run<H>(&mut self, handler: H) -> Result<(), ProtocolError<T::Error>>
142    where
143        P: ClientProtocol<H, T>,
144    {
145        self.client.run(ClientAdapter { handler, _protocol: PhantomData::<P> }).await
146    }
147
148    /// Runs the client, ignoring any incoming events.
149    pub async fn run_sender(&mut self) -> Result<(), ProtocolError<T::Error>> {
150        self.client.run(IgnoreEvents).await
151    }
152}
153
154/// A strongly typed response future.
155pub struct ResponseFuture<
156    'a,
157    M,
158    #[cfg(feature = "fuchsia")] T: Transport = zx::Channel,
159    #[cfg(not(feature = "fuchsia"))] T: Transport,
160> {
161    future: protocol::ResponseFuture<'a, T>,
162    _method: PhantomData<M>,
163}
164
165impl<'a, M, T: Transport> ResponseFuture<'a, M, T> {
166    /// Creates a new response future from an untyped response future.
167    pub fn from_untyped(future: protocol::ResponseFuture<'a, T>) -> Self {
168        Self { future, _method: PhantomData }
169    }
170}
171
172impl<M, T> Future for ResponseFuture<'_, M, T>
173where
174    M: Method,
175    M::Response: Decode<T::RecvBuffer>,
176    T: Transport,
177{
178    type Output = Result<Response<M, T>, Error<T::Error>>;
179
180    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
181        // SAFETY: `self` is pinned, and `future` is a subfield of `self`, so `future` will not be
182        // moved.
183        let future = unsafe { self.map_unchecked_mut(|this| &mut this.future) };
184        if let Poll::Ready(ready) = future.poll(cx)? {
185            Poll::Ready(ready.decode().map_err(Error::Decode))
186        } else {
187            Poll::Pending
188        }
189    }
190}