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 task.
261pub type HandlerTask<T, H, E = <T as HasExecutor>::Executor> =
262    <E as Executor>::Task<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>, HandlerTask<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>, HandlerTask<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        let (client, task) = Self::spawn_handler_full_on_with(self, create_handler, executor);
320        executor.detach(task);
321        client
322    }
323
324    /// Spawns a dispatcher for the given client end with a handler on an
325    /// executor.
326    ///
327    /// Returns the client.
328    pub fn spawn_handler_on<H, E>(self, handler: H, executor: &E) -> Client<P, T>
329    where
330        P: DispatchClientMessage<H, T>,
331        T: 'static,
332        H: Send + 'static,
333        E: Executor,
334    {
335        self.spawn_handler_on_with(|_| handler, executor)
336    }
337
338    /// Spawns a dispatcher for the given client end with a handler computed
339    /// from a closure on the default executor for the transport.
340    ///
341    /// Returns the client and a join handle for the spawned task.
342    pub fn spawn_handler_full_with<H>(
343        self,
344        create_handler: impl FnOnce(Client<P, T>) -> H,
345    ) -> (Client<P, T>, HandlerTask<T, H>)
346    where
347        P: DispatchClientMessage<H, T>,
348        T: HasExecutor + 'static,
349        H: Send + 'static,
350    {
351        let executor = self.executor();
352        Self::spawn_handler_full_on_with(self, create_handler, &executor)
353    }
354
355    /// Spawns a dispatcher for the given client end with a handler on the
356    /// default executor for the transport.
357    ///
358    /// Returns the client and a join handle for the spawned task.
359    pub fn spawn_handler_full<H>(self, handler: H) -> (Client<P, T>, HandlerTask<T, H>)
360    where
361        P: DispatchClientMessage<H, T>,
362        T: HasExecutor + 'static,
363        H: Send + 'static,
364    {
365        self.spawn_handler_full_with(|_| handler)
366    }
367
368    /// Spawns a dispatcher for the given client end with a handler computed
369    /// from a closure on the default executor for the transport.
370    ///
371    /// Returns the client.
372    pub fn spawn_handler_with<H>(
373        self,
374        create_handler: impl FnOnce(Client<P, T>) -> H,
375    ) -> Client<P, T>
376    where
377        P: DispatchClientMessage<H, T>,
378        T: HasExecutor + 'static,
379        H: Send + 'static,
380    {
381        let executor = self.executor();
382        Self::spawn_handler_on_with(self, create_handler, &executor)
383    }
384
385    /// Spawns a dispatcher for the given client end with a handler on the
386    /// default executor for the transport.
387    ///
388    /// Returns the client.
389    pub fn spawn_handler<H>(self, handler: H) -> Client<P, T>
390    where
391        P: DispatchClientMessage<H, T>,
392        T: HasExecutor + 'static,
393        H: Send + 'static,
394    {
395        self.spawn_handler_with(|_| handler)
396    }
397
398    /// Spawns a dispatcher for the given client end on an executor.
399    ///
400    /// The spawned dispatcher will ignore all incoming events. Returns the
401    /// client and a join handle for the spawned task.
402    pub fn spawn_full_on<E>(self, executor: &E) -> (Client<P, T>, HandlerTask<T, (), E>)
403    where
404        P: DispatchClientMessage<IgnoreEvents, T>,
405        T: 'static,
406        E: Executor,
407    {
408        let dispatcher = ClientDispatcher::new(self);
409        let client = dispatcher.client();
410        (client, executor.spawn(dispatcher.run_client()))
411    }
412
413    /// Spawns a dispatcher for the given client end on an executor.
414    ///
415    /// The spawned dispatcher will ignore all incoming events. Returns the
416    /// client.
417    pub fn spawn_on<E>(self, executor: &E) -> Client<P, T>
418    where
419        P: DispatchClientMessage<IgnoreEvents, T>,
420        T: 'static,
421        E: Executor,
422    {
423        let (client, task) = Self::spawn_full_on(self, executor);
424        executor.detach(task);
425        client
426    }
427
428    /// Spawns a dispatcher for the given client end on the default executor for
429    /// the transport.
430    ///
431    /// The spawned dispatcher will ignore all incoming events. Returns the
432    /// client and a join handle for the spawned task.
433    pub fn spawn_full(self) -> (Client<P, T>, HandlerTask<T, ()>)
434    where
435        P: DispatchClientMessage<IgnoreEvents, T>,
436        T: HasExecutor + 'static,
437    {
438        let executor = self.executor();
439        Self::spawn_full_on(self, &executor)
440    }
441
442    /// Spawns a dispatcher for the given client end on the default executor for
443    /// the transport.
444    ///
445    /// The spawned dispatcher will ignore all incoming events. Returns the
446    /// client.
447    pub fn spawn(self) -> Client<P, T>
448    where
449        P: DispatchClientMessage<IgnoreEvents, T>,
450        T: HasExecutor + 'static,
451    {
452        let executor = self.executor();
453        Self::spawn_on(self, &executor)
454    }
455}
456
457impl<P, T: Transport> ServerEnd<P, T> {
458    /// Spawns a dispatcher for the given server end with a handler computed
459    /// from a closure on an executor.
460    ///
461    /// Returns the join handle for the spawned task and the server.
462    pub fn spawn_full_on_with<H, E>(
463        self,
464        create_handler: impl FnOnce(Server<P, T>) -> H,
465        executor: &E,
466    ) -> (HandlerTask<T, H, E>, Server<P, T>)
467    where
468        P: DispatchServerMessage<H, T>,
469        T: 'static,
470        H: Send + 'static,
471        E: Executor,
472    {
473        let dispatcher = ServerDispatcher::new(self);
474        let server = dispatcher.server();
475        let handler = create_handler(server.clone());
476        (executor.spawn(dispatcher.run(handler)), server)
477    }
478
479    /// Spawns a dispatcher for the given server end with a handler on an
480    /// executor.
481    ///
482    /// Returns the join handle for the spawned task and the server.
483    pub fn spawn_full_on<H, E>(
484        self,
485        handler: H,
486        executor: &E,
487    ) -> (HandlerTask<T, H, E>, Server<P, T>)
488    where
489        P: DispatchServerMessage<H, T>,
490        T: 'static,
491        H: Send + 'static,
492        E: Executor,
493    {
494        self.spawn_full_on_with(|_| handler, executor)
495    }
496
497    /// Spawns a dispatcher for the given server end with a handler computed
498    /// from a closure on an executor.
499    ///
500    /// Returns the join handle for the spawned task.
501    pub fn spawn_on_with<H, E>(
502        self,
503        create_handler: impl FnOnce(Server<P, T>) -> H,
504        executor: &E,
505    ) -> HandlerTask<T, H, E>
506    where
507        P: DispatchServerMessage<H, T>,
508        T: 'static,
509        H: Send + 'static,
510        E: Executor,
511    {
512        let dispatcher = ServerDispatcher::new(self);
513        let handler = create_handler(dispatcher.server());
514        executor.spawn(dispatcher.run(handler))
515    }
516
517    /// Spawns a dispatcher for the given server end with a handler on an
518    /// executor.
519    ///
520    /// Returns the join handle for the spawned task.
521    pub fn spawn_on<H, E>(self, handler: H, executor: &E) -> HandlerTask<T, H, E>
522    where
523        P: DispatchServerMessage<H, T>,
524        T: 'static,
525        H: Send + 'static,
526        E: Executor,
527    {
528        self.spawn_on_with(|_| handler, executor)
529    }
530
531    /// Spawns a dispatcher for the given server end with a handler computed
532    /// from a closure on the default executor for the transport.
533    ///
534    /// Returns the join handle for the spawned task and the server.
535    pub fn spawn_full_with<H>(
536        self,
537        create_handler: impl FnOnce(Server<P, T>) -> H,
538    ) -> (HandlerTask<T, H>, Server<P, T>)
539    where
540        P: DispatchServerMessage<H, T>,
541        T: HasExecutor + 'static,
542        H: Send + 'static,
543    {
544        let executor = self.executor();
545        Self::spawn_full_on_with(self, create_handler, &executor)
546    }
547
548    /// Spawns a dispatcher for the given server end with a handler on the
549    /// default executor for the transport.
550    ///
551    /// Returns the join handle for the spawned task and the server.
552    pub fn spawn_full<H>(self, handler: H) -> (HandlerTask<T, H>, Server<P, T>)
553    where
554        P: DispatchServerMessage<H, T>,
555        T: HasExecutor + 'static,
556        H: Send + 'static,
557    {
558        self.spawn_full_with(|_| handler)
559    }
560
561    /// Spawns a dispatcher for the given server end with a handler computed
562    /// from a closure on the default executor for the transport.
563    ///
564    /// Returns the join handle for the spawned task.
565    pub fn spawn_with<H>(self, create_handler: impl FnOnce(Server<P, T>) -> H) -> HandlerTask<T, H>
566    where
567        P: DispatchServerMessage<H, T>,
568        T: HasExecutor + 'static,
569        H: Send + 'static,
570    {
571        let executor = self.executor();
572        Self::spawn_on_with(self, create_handler, &executor)
573    }
574
575    /// Spawns a dispatcher for the given server end with a handler on the
576    /// default executor for the transport.
577    ///
578    /// Returns the join handle for the spawned task.
579    pub fn spawn<H>(self, handler: H) -> HandlerTask<T, H>
580    where
581        P: DispatchServerMessage<H, T>,
582        T: HasExecutor + 'static,
583        H: Send + 'static,
584    {
585        self.spawn_with(|_| handler)
586    }
587}