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