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