fidl_next_bind/
endpoint.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::marker::PhantomData;
6use core::mem::MaybeUninit;
7use core::{concat, stringify};
8
9use fidl_next_codec::{
10    Constrained, Decode, DecodeError, Encode, EncodeError, EncodeOption, FromWire, FromWireOption,
11    FromWireOptionRef, FromWireRef, IntoNatural, Slot, Unconstrained, Wire, munge,
12};
13use fidl_next_protocol::{ProtocolError, Transport};
14
15use crate::{
16    Client, ClientDispatcher, DispatchClientMessage, DispatchServerMessage, Executor, HasExecutor,
17    HasTransport, IgnoreEvents, Server, ServerDispatcher,
18};
19
20macro_rules! endpoint {
21    (
22        #[doc = $doc:literal]
23        $name:ident
24    ) => {
25        #[doc = $doc]
26        #[derive(Debug, PartialEq)]
27        #[repr(transparent)]
28        pub struct $name<
29            P,
30            T = <P as HasTransport>::Transport,
31        > {
32            transport: T,
33            _protocol: PhantomData<P>,
34        }
35
36        unsafe impl<P, T: Send> Send for $name<P, T> {}
37
38        unsafe impl<P, T: Sync> Sync for $name<P, T> {}
39
40        // SAFETY:
41        // - `$name::Owned<'de>` wraps a `T::Owned<'de>`. Because `T: Wire`,
42        //   `T::Owned<'de>` does not yield any references to decoded data that
43        //   outlive `'de`. Therefore, `$name::Owned<'de>` also does not yield
44        //   any references to decoded data that outlive `'de`.
45        // - `$name` is `#[repr(transparent)]` over the transport `T`, and
46        //   `zero_padding` calls `T::zero_padding` on `transport`. `_protocol`
47        //   is a ZST which does not have any padding bytes to zero-initialize.
48        unsafe impl<P: 'static, T: Wire> Wire for $name<P, T> {
49            type Owned<'de> = $name<P, T::Owned<'de>>;
50
51            #[inline]
52            fn zero_padding(out: &mut MaybeUninit<Self>) {
53                munge!(let Self { transport, _protocol: _ } = out);
54                T::zero_padding(transport);
55            }
56        }
57
58        impl<P, T> $name<P, T> {
59            #[doc = concat!(
60                "Converts from `&",
61                stringify!($name),
62                "<P, T>` to `",
63                stringify!($name),
64                "<P, &T>`.",
65            )]
66            pub fn as_ref(&self) -> $name<P, &T> {
67                $name { transport: &self.transport, _protocol: PhantomData }
68            }
69
70            /// Returns a new endpoint over the given transport.
71            pub fn from_untyped(transport: T) -> Self {
72                Self { transport, _protocol: PhantomData }
73            }
74
75            /// Returns the underlying transport.
76            pub fn into_untyped(self) -> T {
77                self.transport
78            }
79
80            /// Returns the executor for the underlying transport.
81            pub fn executor(&self) -> T::Executor
82            where
83                T: HasExecutor,
84            {
85                self.transport.executor()
86            }
87        }
88
89        // SAFETY: `$name` is `#[repr(transparent)]` over the transport `T`, and `decode` calls
90        // `T::decode` on `transport`. `_protocol` is a ZST which does not have any data to decode.
91        unsafe impl<D, P, T> Decode<D> for $name<P, T>
92        where
93            D: ?Sized,
94            P: 'static,
95            T: Decode<D>,
96            T: Constrained<Constraint=()>,
97        {
98            fn decode(slot: Slot<'_, Self>, decoder: &mut D, constraint:  <Self as Constrained>::Constraint) -> Result<(), DecodeError> {
99                munge!(let Self { transport, _protocol: _ } = slot);
100                T::decode(transport, decoder, constraint)
101            }
102        }
103
104        // SAFETY: `$name` is `#[repr(transparent)]` over the transport `T`, and `encode` calls
105        // `T::encode` on `transport`. `_protocol` is a ZST which does not have any data to encode.
106        unsafe impl<W, E, P, T> Encode<$name<P, W>, E> for $name<P, T>
107        where
108            E: ?Sized,
109            P: 'static,
110            T: Encode<W, E>,
111            W: Constrained<Constraint = ()> + Wire,
112        {
113            fn encode(
114                self,
115                encoder: &mut E,
116                out: &mut MaybeUninit<$name<P, W>>,
117                constraint:  (),
118            ) -> Result<(), EncodeError> {
119                munge!(let $name { transport, _protocol: _ } = out);
120                self.transport.encode(encoder, transport, constraint)
121            }
122        }
123
124        // SAFETY: `$name` is `#[repr(transparent)]` over the transport `T`, and `encode_ref` calls
125        // `T::encode_ref` on `transport`. `_protocol` is a ZST which does not have any data to
126        // encode.
127        unsafe impl<'a, W, E, P, T> Encode<$name<P, W>, E> for &'a $name<P, T>
128        where
129            E: ?Sized,
130            P: 'static,
131            &'a T: Encode<W, E>,
132            W: Constrained<Constraint = ()> + Wire,
133        {
134            fn encode(
135                self,
136                encoder: &mut E,
137                out: &mut MaybeUninit<$name<P, W>>,
138                constraint:  (),
139            ) -> Result<(), EncodeError> {
140                self.as_ref().encode(encoder, out, constraint)
141            }
142        }
143
144        // SAFETY: `$name` is `#[repr(transparent)]` over the transport `T`, and `encode_option`
145        // calls `T::encode_option` on `transport`. `_protocol` is a ZST which does not have any
146        // data to encode.
147        unsafe impl<W, E, P, T> EncodeOption<$name<P, W>, E> for $name<P, T>
148        where
149            E: ?Sized,
150            P: 'static,
151            T: EncodeOption<W, E>,
152            W: Constrained<Constraint = ()>
153        {
154            fn encode_option(
155                this: Option<Self>,
156                encoder: &mut E,
157                out: &mut MaybeUninit<$name<P, W>>,
158                constraint: (),
159            ) -> Result<(), EncodeError> {
160                munge!(let $name { transport, _protocol: _ } = out);
161                T::encode_option(this.map(|this| this.transport), encoder, transport, constraint)
162            }
163        }
164
165        // SAFETY: `$name` is `#[repr(transparent)]` over the transport `T`, and `encode_option_ref`
166        // calls `T::encode_option_ref` on `transport`. `_protocol` is a ZST which does not have any
167        // data to encode.
168        unsafe impl<'a, W, E, P, T> EncodeOption<$name<P, W>, E> for &'a $name<P, T>
169        where
170            E: ?Sized,
171            P: 'static,
172            &'a T: EncodeOption<W, E>,
173            W: Constrained<Constraint = ()>
174        {
175            fn encode_option(
176                this: Option<Self>,
177                encoder: &mut E,
178                out: &mut MaybeUninit<$name<P, W>>,
179                constraint:  (),
180            ) -> Result<(), EncodeError> {
181                munge!(let $name { transport, _protocol: _ } = out);
182                <&T>::encode_option(this.map(|this| &this.transport), encoder, transport, constraint)
183            }
184        }
185
186        impl<P, T: Constrained<Constraint = ()>> Unconstrained for $name<P, T> {}
187
188        impl<P, T, U> FromWire<$name<P, U>> for $name<P, T>
189        where
190            T: FromWire<U>,
191        {
192            #[inline]
193            fn from_wire(wire: $name<P, U>) -> Self {
194                $name {
195                    transport: T::from_wire(wire.transport),
196                    _protocol: PhantomData,
197                }
198            }
199        }
200
201        impl<P, T: IntoNatural> IntoNatural for $name<P, T> {
202            type Natural = $name<P, T::Natural>;
203        }
204
205        impl<P, T, U> FromWireRef<$name<P, U>> for $name<P, T>
206        where
207            T: FromWireRef<U>,
208        {
209            #[inline]
210            fn from_wire_ref(wire: &$name<P, U>) -> Self {
211                $name {
212                    transport: T::from_wire_ref(&wire.transport),
213                    _protocol: PhantomData,
214                }
215            }
216        }
217
218        impl<P, T, U> FromWireOption<$name<P, U>> for $name<P, T>
219        where
220            P: 'static,
221            T: FromWireOption<U>,
222            U: Wire,
223        {
224            #[inline]
225            fn from_wire_option(wire: $name<P, U>) -> Option<Self> {
226                T::from_wire_option(wire.transport).map(|transport| $name {
227                    transport,
228                    _protocol: PhantomData,
229                })
230            }
231        }
232
233        impl<P, T, U> FromWireOptionRef<$name<P, U>> for $name<P, T>
234        where
235            P: 'static,
236            T: FromWireOptionRef<U>,
237            U: Wire,
238        {
239            #[inline]
240            fn from_wire_option_ref(wire: &$name<P, U>) -> Option<Self> {
241                T::from_wire_option_ref(&wire.transport).map(|transport| $name {
242                    transport,
243                    _protocol: PhantomData,
244                })
245            }
246        }
247    };
248}
249
250endpoint! {
251    /// The client end of a protocol.
252    ClientEnd
253}
254
255endpoint! {
256    /// The server end of a protocol.
257    ServerEnd
258}
259
260/// A client or server handler join handle.
261pub type HandlerJoinHandle<T, H, E = <T as HasExecutor>::Executor> =
262    <E as Executor>::JoinHandle<Result<H, ProtocolError<<T as Transport>::Error>>>;
263
264impl<P, T: Transport> ClientEnd<P, T> {
265    /// Spawns a dispatcher for the given client end with a handler computed
266    /// from a closure on an executor.
267    ///
268    /// Returns the client and a join handle for the spawned task.
269    pub fn spawn_handler_full_on_with<H, E>(
270        self,
271        create_handler: impl FnOnce(Client<P, T>) -> H,
272        executor: &E,
273    ) -> (Client<P, T>, HandlerJoinHandle<T, H, E>)
274    where
275        P: DispatchClientMessage<H, T>,
276        T: 'static,
277        H: Send + 'static,
278        E: Executor,
279    {
280        let dispatcher = ClientDispatcher::new(self);
281        let client = dispatcher.client();
282        let handler = create_handler(client.clone());
283        (client, executor.spawn(dispatcher.run(handler)))
284    }
285
286    /// Spawns a dispatcher for the given client end with a handler on an
287    /// executor.
288    ///
289    /// Returns the client and a join handle for the spawned task.
290    pub fn spawn_handler_full_on<H, E>(
291        self,
292        handler: H,
293        executor: &E,
294    ) -> (Client<P, T>, HandlerJoinHandle<T, H, E>)
295    where
296        P: DispatchClientMessage<H, T>,
297        T: 'static,
298        H: Send + 'static,
299        E: Executor,
300    {
301        self.spawn_handler_full_on_with(|_| handler, executor)
302    }
303
304    /// Spawns a dispatcher for the given client end with a handler computed
305    /// from a closure on an executor.
306    ///
307    /// Returns the client.
308    pub fn spawn_handler_on_with<H, E>(
309        self,
310        create_handler: impl FnOnce(Client<P, T>) -> H,
311        executor: &E,
312    ) -> Client<P, T>
313    where
314        P: DispatchClientMessage<H, T>,
315        T: 'static,
316        H: Send + 'static,
317        E: Executor,
318    {
319        Self::spawn_handler_full_on_with(self, create_handler, executor).0
320    }
321
322    /// Spawns a dispatcher for the given client end with a handler on an
323    /// executor.
324    ///
325    /// Returns the client.
326    pub fn spawn_handler_on<H, E>(self, handler: H, executor: &E) -> Client<P, T>
327    where
328        P: DispatchClientMessage<H, T>,
329        T: 'static,
330        H: Send + 'static,
331        E: Executor,
332    {
333        self.spawn_handler_on_with(|_| handler, executor)
334    }
335
336    /// Spawns a dispatcher for the given client end with a handler computed
337    /// from a closure on the default executor for the transport.
338    ///
339    /// Returns the client and a join handle for the spawned task.
340    pub fn spawn_handler_full_with<H>(
341        self,
342        create_handler: impl FnOnce(Client<P, T>) -> H,
343    ) -> (Client<P, T>, HandlerJoinHandle<T, H>)
344    where
345        P: DispatchClientMessage<H, T>,
346        T: HasExecutor + 'static,
347        H: Send + 'static,
348    {
349        let executor = self.executor();
350        Self::spawn_handler_full_on_with(self, create_handler, &executor)
351    }
352
353    /// Spawns a dispatcher for the given client end with a handler on the
354    /// default executor for the transport.
355    ///
356    /// Returns the client and a join handle for the spawned task.
357    pub fn spawn_handler_full<H>(self, handler: H) -> (Client<P, T>, HandlerJoinHandle<T, H>)
358    where
359        P: DispatchClientMessage<H, T>,
360        T: HasExecutor + 'static,
361        H: Send + 'static,
362    {
363        self.spawn_handler_full_with(|_| handler)
364    }
365
366    /// Spawns a dispatcher for the given client end with a handler computed
367    /// from a closure on the default executor for the transport.
368    ///
369    /// Returns the client.
370    pub fn spawn_handler_with<H>(
371        self,
372        create_handler: impl FnOnce(Client<P, T>) -> H,
373    ) -> Client<P, T>
374    where
375        P: DispatchClientMessage<H, T>,
376        T: HasExecutor + 'static,
377        H: Send + 'static,
378    {
379        let executor = self.executor();
380        Self::spawn_handler_on_with(self, create_handler, &executor)
381    }
382
383    /// Spawns a dispatcher for the given client end with a handler on the
384    /// default executor for the transport.
385    ///
386    /// Returns the client.
387    pub fn spawn_handler<H>(self, handler: H) -> Client<P, T>
388    where
389        P: DispatchClientMessage<H, T>,
390        T: HasExecutor + 'static,
391        H: Send + 'static,
392    {
393        self.spawn_handler_with(|_| handler)
394    }
395
396    /// Spawns a dispatcher for the given client end on an executor.
397    ///
398    /// The spawned dispatcher will ignore all incoming events. Returns the
399    /// client and a join handle for the spawned task.
400    pub fn spawn_full_on<E>(self, executor: &E) -> (Client<P, T>, HandlerJoinHandle<T, (), E>)
401    where
402        P: DispatchClientMessage<IgnoreEvents, T>,
403        T: 'static,
404        E: Executor,
405    {
406        let dispatcher = ClientDispatcher::new(self);
407        let client = dispatcher.client();
408        (client, executor.spawn(dispatcher.run_client()))
409    }
410
411    /// Spawns a dispatcher for the given client end on an executor.
412    ///
413    /// The spawned dispatcher will ignore all incoming events. Returns the
414    /// client.
415    pub fn spawn_on<E>(self, executor: &E) -> Client<P, T>
416    where
417        P: DispatchClientMessage<IgnoreEvents, T>,
418        T: 'static,
419        E: Executor,
420    {
421        Self::spawn_full_on(self, executor).0
422    }
423
424    /// Spawns a dispatcher for the given client end on the default executor for
425    /// the transport.
426    ///
427    /// The spawned dispatcher will ignore all incoming events. Returns the
428    /// client and a join handle for the spawned task.
429    pub fn spawn_full(self) -> (Client<P, T>, HandlerJoinHandle<T, ()>)
430    where
431        P: DispatchClientMessage<IgnoreEvents, T>,
432        T: HasExecutor + 'static,
433    {
434        let executor = self.executor();
435        Self::spawn_full_on(self, &executor)
436    }
437
438    /// Spawns a dispatcher for the given client end on the default executor for
439    /// the transport.
440    ///
441    /// The spawned dispatcher will ignore all incoming events. Returns the
442    /// client.
443    pub fn spawn(self) -> Client<P, T>
444    where
445        P: DispatchClientMessage<IgnoreEvents, T>,
446        T: HasExecutor + 'static,
447    {
448        let executor = self.executor();
449        Self::spawn_on(self, &executor)
450    }
451}
452
453impl<P, T: Transport> ServerEnd<P, T> {
454    /// Spawns a dispatcher for the given server end with a handler computed
455    /// from a closure on an executor.
456    ///
457    /// Returns the join handle for the spawned task and the server.
458    pub fn spawn_full_on_with<H, E>(
459        self,
460        create_handler: impl FnOnce(Server<P, T>) -> H,
461        executor: &E,
462    ) -> (HandlerJoinHandle<T, H, E>, Server<P, T>)
463    where
464        P: DispatchServerMessage<H, T>,
465        T: 'static,
466        H: Send + 'static,
467        E: Executor,
468    {
469        let dispatcher = ServerDispatcher::new(self);
470        let server = dispatcher.server();
471        let handler = create_handler(server.clone());
472        (executor.spawn(dispatcher.run(handler)), server)
473    }
474
475    /// Spawns a dispatcher for the given server end with a handler on an
476    /// executor.
477    ///
478    /// Returns the join handle for the spawned task and the server.
479    pub fn spawn_full_on<H, E>(
480        self,
481        handler: H,
482        executor: &E,
483    ) -> (HandlerJoinHandle<T, H, E>, Server<P, T>)
484    where
485        P: DispatchServerMessage<H, T>,
486        T: 'static,
487        H: Send + 'static,
488        E: Executor,
489    {
490        self.spawn_full_on_with(|_| handler, executor)
491    }
492
493    /// Spawns a dispatcher for the given server end with a handler computed
494    /// from a closure on an executor.
495    ///
496    /// Returns the join handle for the spawned task.
497    pub fn spawn_on_with<H, E>(
498        self,
499        create_handler: impl FnOnce(Server<P, T>) -> H,
500        executor: &E,
501    ) -> HandlerJoinHandle<T, H, E>
502    where
503        P: DispatchServerMessage<H, T>,
504        T: 'static,
505        H: Send + 'static,
506        E: Executor,
507    {
508        let dispatcher = ServerDispatcher::new(self);
509        let handler = create_handler(dispatcher.server());
510        executor.spawn(dispatcher.run(handler))
511    }
512
513    /// Spawns a dispatcher for the given server end with a handler on an
514    /// executor.
515    ///
516    /// Returns the join handle for the spawned task.
517    pub fn spawn_on<H, E>(self, handler: H, executor: &E) -> HandlerJoinHandle<T, H, E>
518    where
519        P: DispatchServerMessage<H, T>,
520        T: 'static,
521        H: Send + 'static,
522        E: Executor,
523    {
524        self.spawn_on_with(|_| handler, executor)
525    }
526
527    /// Spawns a dispatcher for the given server end with a handler computed
528    /// from a closure on the default executor for the transport.
529    ///
530    /// Returns the join handle for the spawned task and the server.
531    pub fn spawn_full_with<H>(
532        self,
533        create_handler: impl FnOnce(Server<P, T>) -> H,
534    ) -> (HandlerJoinHandle<T, H>, Server<P, T>)
535    where
536        P: DispatchServerMessage<H, T>,
537        T: HasExecutor + 'static,
538        H: Send + 'static,
539    {
540        let executor = self.executor();
541        Self::spawn_full_on_with(self, create_handler, &executor)
542    }
543
544    /// Spawns a dispatcher for the given server end with a handler on the
545    /// default executor for the transport.
546    ///
547    /// Returns the join handle for the spawned task and the server.
548    pub fn spawn_full<H>(self, handler: H) -> (HandlerJoinHandle<T, H>, Server<P, T>)
549    where
550        P: DispatchServerMessage<H, T>,
551        T: HasExecutor + 'static,
552        H: Send + 'static,
553    {
554        self.spawn_full_with(|_| handler)
555    }
556
557    /// Spawns a dispatcher for the given server end with a handler computed
558    /// from a closure on the default executor for the transport.
559    ///
560    /// Returns the join handle for the spawned task.
561    pub fn spawn_with<H>(
562        self,
563        create_handler: impl FnOnce(Server<P, T>) -> H,
564    ) -> HandlerJoinHandle<T, H>
565    where
566        P: DispatchServerMessage<H, T>,
567        T: HasExecutor + 'static,
568        H: Send + 'static,
569    {
570        let executor = self.executor();
571        Self::spawn_on_with(self, create_handler, &executor)
572    }
573
574    /// Spawns a dispatcher for the given server end with a handler on the
575    /// default executor for the transport.
576    ///
577    /// Returns the join handle for the spawned task.
578    pub fn spawn<H>(self, handler: H) -> HandlerJoinHandle<T, H>
579    where
580        P: DispatchServerMessage<H, T>,
581        T: HasExecutor + 'static,
582        H: Send + 'static,
583    {
584        self.spawn_with(|_| handler)
585    }
586}