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