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