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