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    munge, Decode, DecodeError, Encodable, EncodableOption, Encode, EncodeError, EncodeOption,
11    EncodeRef, FromWire, FromWireOption, FromWireOptionRef, FromWireRef, Slot, Wire,
12};
13
14macro_rules! endpoint {
15    (
16        #[doc = $doc:literal]
17        $name:ident
18    ) => {
19        #[doc = $doc]
20        #[derive(Debug)]
21        #[repr(transparent)]
22        pub struct $name<
23            P,
24            #[cfg(feature = "fuchsia")]
25            T = zx::Channel,
26            #[cfg(not(feature = "fuchsia"))]
27            T,
28        > {
29            transport: T,
30            _protocol: PhantomData<P>,
31        }
32
33        // SAFETY:
34        // - `$name::Decoded<'de>` wraps a `T::Decoded<'de>`. Because `T: Wire`, `T::Decoded<'de>`
35        //   does not yield any references to decoded data that outlive `'de`. Therefore,
36        //   `$name::Decoded<'de>` also does not yield any references to decoded data that outlive
37        //   `'de`.
38        // - `$name` is `#[repr(transparent)]` over the transport `T`, and `zero_padding` calls
39        //   `T::zero_padding` on `transport`. `_protocol` is a ZST which does not have any padding
40        //   bytes to zero-initialize.
41        unsafe impl<P: 'static, T: Wire> Wire for $name<P, T> {
42            type Decoded<'de> = $name<P, T::Decoded<'de>>;
43
44            #[inline]
45            fn zero_padding(out: &mut MaybeUninit<Self>) {
46                munge!(let Self { transport, _protocol: _ } = out);
47                T::zero_padding(transport);
48            }
49        }
50
51        impl<P, T> $name<P, T> {
52            #[doc = concat!(
53                "Converts from `&",
54                stringify!($name),
55                "<P, T>` to `",
56                stringify!($name),
57                "<P, &T>`.",
58            )]
59            pub fn as_ref(&self) -> $name<P, &T> {
60                $name { transport: &self.transport, _protocol: PhantomData }
61            }
62
63            /// Returns a new endpoint over the given transport.
64            pub fn from_untyped(transport: T) -> Self {
65                Self { transport, _protocol: PhantomData }
66            }
67
68            /// Returns the underlying transport.
69            pub fn into_untyped(self) -> T {
70                self.transport
71            }
72        }
73
74        // SAFETY: `$name` is `#[repr(transparent)]` over the transport `T`, and `decode` calls
75        // `T::decode` on `transport`. `_protocol` is a ZST which does not have any data to decode.
76        unsafe impl<D, P, T> Decode<D> for $name<P, T>
77        where
78            D: ?Sized,
79            P: 'static,
80            T: Decode<D>,
81        {
82            fn decode(slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
83                munge!(let Self { transport, _protocol: _ } = slot);
84                T::decode(transport, decoder)
85            }
86        }
87
88        impl<P, T> Encodable for $name<P, T>
89        where
90            T: Encodable,
91            P: 'static,
92        {
93            type Encoded = $name<P, T::Encoded>;
94        }
95
96        impl<P, T> EncodableOption for $name<P, T>
97        where
98            T: EncodableOption,
99            P: 'static,
100        {
101            type EncodedOption = $name<P, T::EncodedOption>;
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<E, P, T> Encode<E> for $name<P, T>
107        where
108            E: ?Sized,
109            P: 'static,
110            T: Encode<E>,
111        {
112            fn encode(
113                self,
114                encoder: &mut E,
115                out: &mut MaybeUninit<Self::Encoded>,
116            ) -> Result<(), EncodeError> {
117                munge!(let Self::Encoded { transport, _protocol: _ } = out);
118                self.transport.encode(encoder, transport)
119            }
120        }
121
122        // SAFETY: `$name` is `#[repr(transparent)]` over the transport `T`, and `encode_ref` calls
123        // `T::encode_ref` on `transport`. `_protocol` is a ZST which does not have any data to
124        // encode.
125        unsafe impl<E, P, T> EncodeRef<E> for $name<P, T>
126        where
127            E: ?Sized,
128            P: 'static,
129            T: EncodeRef<E>,
130        {
131            fn encode_ref(
132                &self,
133                encoder: &mut E,
134                out: &mut MaybeUninit<Self::Encoded>,
135            ) -> Result<(), EncodeError> {
136                self.as_ref().encode(encoder, out)
137            }
138        }
139
140        // SAFETY: `$name` is `#[repr(transparent)]` over the transport `T`, and `encode_option`
141        // calls `T::encode_option` on `transport`. `_protocol` is a ZST which does not have any
142        // data to encode.
143        unsafe impl<E, P, T> EncodeOption<E> for $name<P, T>
144        where
145            E: ?Sized,
146            P: 'static,
147            T: EncodeOption<E>,
148        {
149            fn encode_option(
150                this: Option<Self>,
151                encoder: &mut E,
152                out: &mut MaybeUninit<Self::EncodedOption>,
153            ) -> Result<(), EncodeError> {
154                munge!(let Self::EncodedOption { transport, _protocol: _ } = out);
155                T::encode_option(this.map(|this| this.transport), encoder, transport)
156            }
157        }
158
159        impl<P, T, U> FromWire<$name<P, U>> for $name<P, T>
160        where
161            T: FromWire<U>,
162        {
163            #[inline]
164            fn from_wire(wire: $name<P, U>) -> Self {
165                $name {
166                    transport: T::from_wire(wire.transport),
167                    _protocol: PhantomData,
168                }
169            }
170        }
171
172        impl<P, T, U> FromWireRef<$name<P, U>> for $name<P, T>
173        where
174            T: FromWireRef<U>,
175        {
176            #[inline]
177            fn from_wire_ref(wire: &$name<P, U>) -> Self {
178                $name {
179                    transport: T::from_wire_ref(&wire.transport),
180                    _protocol: PhantomData,
181                }
182            }
183        }
184
185        impl<P, T, U> FromWireOption<$name<P, U>> for $name<P, T>
186        where
187            P: 'static,
188            T: FromWireOption<U>,
189            U: Wire,
190        {
191            #[inline]
192            fn from_wire_option(wire: $name<P, U>) -> Option<Self> {
193                T::from_wire_option(wire.transport).map(|transport| $name {
194                    transport,
195                    _protocol: PhantomData,
196                })
197            }
198        }
199
200        impl<P, T, U> FromWireOptionRef<$name<P, U>> for $name<P, T>
201        where
202            P: 'static,
203            T: FromWireOptionRef<U>,
204            U: Wire,
205        {
206            #[inline]
207            fn from_wire_option_ref(wire: &$name<P, U>) -> Option<Self> {
208                T::from_wire_option_ref(&wire.transport).map(|transport| $name {
209                    transport,
210                    _protocol: PhantomData,
211                })
212            }
213        }
214
215        #[cfg(feature = "compat")]
216        impl<P1, P2, T> From<$name<P1, T>> for ::fidl::endpoints::$name<P2>
217        where
218            ::fidl::Channel: From<T>,
219            P2: From<P1>,
220        {
221            fn from(from: $name<P1, T>) -> Self {
222                Self::new(from.transport.into())
223            }
224        }
225    };
226}
227
228endpoint! {
229    /// The client end of a protocol.
230    ClientEnd
231}
232
233endpoint! {
234    /// The server end of a protocol.
235    ServerEnd
236}