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