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