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, 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 handler.
58pub trait DispatchClientMessage<H, T: Transport>: Sized + 'static {
59    /// Handles a received client event with the given handler.
60    fn on_event(
61        handler: &mut H,
62        ordinal: u64,
63        flexibility: Flexibility,
64        body: Body<T>,
65    ) -> impl Future<Output = Result<(), ProtocolError<T::Error>>> + Send;
66}
67
68/// An adapter for a client protocol handler.
69pub struct ClientHandlerAdapter<P, H> {
70    handler: H,
71    _protocol: PhantomData<P>,
72}
73
74unsafe impl<P, H> Send for ClientHandlerAdapter<P, H> where H: Send {}
75
76impl<P, H> ClientHandlerAdapter<P, H> {
77    /// Creates a new protocol client handler from a supported handler.
78    pub fn from_untyped(handler: H) -> Self {
79        Self { handler, _protocol: PhantomData }
80    }
81}
82
83impl<P, H, T> ClientHandler<T> for ClientHandlerAdapter<P, H>
84where
85    P: DispatchClientMessage<H, T>,
86    T: Transport,
87{
88    fn on_event(
89        &mut self,
90        ordinal: u64,
91        flexibility: Flexibility,
92        body: Body<T>,
93    ) -> impl Future<Output = Result<(), ProtocolError<T::Error>>> + Send {
94        P::on_event(&mut self.handler, ordinal, flexibility, body)
95    }
96}
97
98/// A strongly typed client dispatcher.
99pub struct ClientDispatcher<P, T: Transport = <P as HasTransport>::Transport> {
100    dispatcher: protocol::ClientDispatcher<T>,
101    _protocol: PhantomData<P>,
102}
103
104unsafe impl<P, T> Send for ClientDispatcher<P, T>
105where
106    T: Transport,
107    protocol::Client<T>: Send,
108{
109}
110
111impl<P, T: Transport> ClientDispatcher<P, T> {
112    /// Creates a new client from a client end.
113    pub fn new(client_end: ClientEnd<P, T>) -> Self {
114        Self {
115            dispatcher: protocol::ClientDispatcher::new(client_end.into_untyped()),
116            _protocol: PhantomData,
117        }
118    }
119
120    /// Returns the dispatcher's client.
121    pub fn client(&self) -> Client<P, T> {
122        Client::from_untyped(self.dispatcher.client())
123    }
124
125    /// Creates a new client from an untyped client.
126    pub fn from_untyped(dispatcher: protocol::ClientDispatcher<T>) -> Self {
127        Self { dispatcher, _protocol: PhantomData }
128    }
129
130    /// Runs the client with the provided handler.
131    pub async fn run<H>(self, handler: H) -> Result<H, ProtocolError<T::Error>>
132    where
133        P: DispatchClientMessage<H, T>,
134    {
135        self.dispatcher
136            .run(ClientHandlerAdapter { handler, _protocol: PhantomData::<P> })
137            .await
138            .map(|adapter| adapter.handler)
139    }
140
141    /// Runs the client, ignoring any incoming events.
142    pub async fn run_client(self) -> Result<(), ProtocolError<T::Error>>
143    where
144        P: DispatchClientMessage<IgnoreEvents, T>,
145    {
146        self.run(IgnoreEvents).await.map(|_| ())
147    }
148}
149
150/// A handler which ignores incoming events.
151pub struct IgnoreEvents;