Skip to main content

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::{
10    self as protocol, ClientHandler, LocalClientHandler, Message, ProtocolError, Transport,
11};
12
13use crate::{ClientEnd, HasConnectionHandles, HasTransport};
14
15/// A strongly typed client.
16#[repr(transparent)]
17pub struct Client<P, T: Transport = <P as HasTransport>::Transport> {
18    client: protocol::Client<T>,
19    _protocol: PhantomData<P>,
20}
21
22unsafe impl<P, T> Send for Client<P, T>
23where
24    T: Transport,
25    protocol::Client<T>: Send,
26{
27}
28
29impl<P, T: Transport> Client<P, T> {
30    /// Creates a new client handle from an untyped client handle.
31    pub fn from_untyped(client: protocol::Client<T>) -> Self {
32        Self { client, _protocol: PhantomData }
33    }
34
35    /// Closes the channel from the client end.
36    pub fn close(&self) {
37        self.client.close();
38    }
39}
40
41impl<P, T: Transport> Clone for Client<P, T> {
42    fn clone(&self) -> Self {
43        Self { client: self.client.clone(), _protocol: PhantomData }
44    }
45}
46
47impl<P: HasConnectionHandles<T>, T: Transport> Deref for Client<P, T> {
48    type Target = P::Client;
49
50    fn deref(&self) -> &Self::Target {
51        // SAFETY: `P::Client` is a `#[repr(transparent)]` wrapper around
52        // `Client<T>`.
53        unsafe { &*(self as *const Self).cast::<P::Client>() }
54    }
55}
56
57/// A protocol which dispatches incoming client messages to a local handler.
58///
59/// This is a variant of [`DispatchClientMessage`] that does not require
60/// implementing `Send` and only supports local-thread executors.
61pub trait DispatchLocalClientMessage<H, T: Transport>: Sized + 'static {
62    /// Handles a received client event with the given handler.
63    fn on_event(
64        handler: &mut H,
65        message: Message<T>,
66    ) -> impl Future<Output = Result<(), ProtocolError<T::Error>>>;
67}
68
69/// A protocol which dispatches incoming client messages to a handler.
70pub trait DispatchClientMessage<H: Send, T: Transport>: Sized + 'static {
71    /// Handles a received client event with the given handler.
72    fn on_event(
73        handler: &mut H,
74        message: Message<T>,
75    ) -> impl Future<Output = Result<(), ProtocolError<T::Error>>> + Send;
76}
77
78/// An adapter for a client protocol handler.
79pub struct ClientHandlerToProtocolAdapter<P, H> {
80    handler: H,
81    _protocol: PhantomData<P>,
82}
83
84unsafe impl<P, H> Send for ClientHandlerToProtocolAdapter<P, H> where H: Send {}
85
86impl<P, H> ClientHandlerToProtocolAdapter<P, H> {
87    /// Creates a new protocol client handler from a supported handler.
88    pub fn from_untyped(handler: H) -> Self {
89        Self { handler, _protocol: PhantomData }
90    }
91}
92
93impl<P, H, T> LocalClientHandler<T> for ClientHandlerToProtocolAdapter<P, H>
94where
95    P: DispatchLocalClientMessage<H, T>,
96    T: Transport,
97{
98    fn on_event(
99        &mut self,
100        message: Message<T>,
101    ) -> impl Future<Output = Result<(), ProtocolError<T::Error>>> {
102        P::on_event(&mut self.handler, message)
103    }
104}
105
106impl<P, H, T> ClientHandler<T> for ClientHandlerToProtocolAdapter<P, H>
107where
108    P: DispatchClientMessage<H, T>,
109    H: Send,
110    T: Transport,
111{
112    fn on_event(
113        &mut self,
114        message: Message<T>,
115    ) -> impl Future<Output = Result<(), ProtocolError<T::Error>>> + Send {
116        P::on_event(&mut self.handler, message)
117    }
118}
119
120/// A strongly typed client dispatcher.
121pub struct ClientDispatcher<P, T: Transport = <P as HasTransport>::Transport> {
122    dispatcher: protocol::ClientDispatcher<T>,
123    _protocol: PhantomData<P>,
124}
125
126unsafe impl<P, T> Send for ClientDispatcher<P, T>
127where
128    T: Transport,
129    protocol::Client<T>: Send,
130{
131}
132
133impl<P, T: Transport> ClientDispatcher<P, T> {
134    /// Creates a new client from a client end.
135    pub fn new(client_end: ClientEnd<P, T>) -> Self {
136        Self {
137            dispatcher: protocol::ClientDispatcher::new(client_end.into_untyped()),
138            _protocol: PhantomData,
139        }
140    }
141
142    /// Returns the dispatcher's client.
143    pub fn client(&self) -> Client<P, T> {
144        Client::from_untyped(self.dispatcher.client())
145    }
146
147    /// Creates a new client from an untyped client.
148    pub fn from_untyped(dispatcher: protocol::ClientDispatcher<T>) -> Self {
149        Self { dispatcher, _protocol: PhantomData }
150    }
151
152    /// Runs the client with the provided handler.
153    pub async fn run<H>(self, handler: H) -> Result<H, ProtocolError<T::Error>>
154    where
155        P: DispatchClientMessage<H, T>,
156        H: Send,
157    {
158        self.dispatcher
159            .run(ClientHandlerToProtocolAdapter { handler, _protocol: PhantomData::<P> })
160            .await
161            .map(|adapter| adapter.handler)
162    }
163
164    /// Runs the client locally with the provided handler.
165    pub async fn run_local<H>(self, handler: H) -> Result<H, ProtocolError<T::Error>>
166    where
167        P: DispatchLocalClientMessage<H, T>,
168    {
169        self.dispatcher
170            .run_local(ClientHandlerToProtocolAdapter { handler, _protocol: PhantomData::<P> })
171            .await
172            .map(|adapter| adapter.handler)
173    }
174
175    /// Runs the client, ignoring any incoming events.
176    pub async fn run_client(self) -> Result<(), ProtocolError<T::Error>>
177    where
178        P: DispatchClientMessage<IgnoreEvents, T>,
179    {
180        self.run(IgnoreEvents).await.map(|_| ())
181    }
182}
183
184/// A handler which ignores incoming events.
185pub struct IgnoreEvents;