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