fidl_next_codec/wire/
envelope.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::mem::{ManuallyDrop, MaybeUninit};
6use core::ptr::addr_of_mut;
7
8use munge::munge;
9
10use crate::decoder::InternalHandleDecoder;
11use crate::encoder::InternalHandleEncoder;
12use crate::{
13    Decode, DecodeError, Decoder, DecoderExt as _, Encode, EncodeError, Encoder, EncoderExt as _,
14    Slot, WireU16, WireU32, CHUNK_SIZE,
15};
16
17#[derive(Clone, Copy)]
18#[repr(C)]
19struct Encoded {
20    maybe_num_bytes: WireU32,
21    num_handles: WireU16,
22    flags: WireU16,
23}
24
25/// A FIDL envelope
26#[repr(C, align(8))]
27pub union WireEnvelope {
28    zero: [u8; 8],
29    encoded: Encoded,
30    decoded_inline: [MaybeUninit<u8>; 4],
31    decoded_out_of_line: *mut (),
32}
33
34impl WireEnvelope {
35    const IS_INLINE_BIT: u16 = 1;
36
37    /// Encodes a zero envelope into a slot.
38    #[inline]
39    pub fn encode_zero(slot: Slot<'_, Self>) {
40        munge!(let Self { mut zero } = slot);
41        *zero = [0; 8];
42    }
43
44    /// Encodes a `'static` value into an envelope with an encoder.
45    #[inline]
46    pub fn encode_value_static<E: InternalHandleEncoder + ?Sized, T: Encode<E>>(
47        value: &mut T,
48        encoder: &mut E,
49        slot: Slot<'_, Self>,
50    ) -> Result<(), EncodeError> {
51        munge! {
52            let Self {
53                encoded: Encoded {
54                    mut maybe_num_bytes,
55                    mut num_handles,
56                    mut flags,
57                },
58            } = slot;
59        }
60
61        let handles_before = encoder.__internal_handle_count();
62
63        if size_of::<T::Encoded>() > 4 {
64            return Err(EncodeError::ExpectedInline(size_of::<T::Encoded>()));
65        }
66
67        let slot = unsafe { Slot::new_unchecked(maybe_num_bytes.as_mut_ptr().cast()) };
68        value.encode(encoder, slot)?;
69
70        **flags = Self::IS_INLINE_BIT;
71
72        **num_handles = (encoder.__internal_handle_count() - handles_before).try_into().unwrap();
73
74        Ok(())
75    }
76
77    /// Encodes a value into an envelope with an encoder.
78    #[inline]
79    pub fn encode_value<E: Encoder + ?Sized, T: Encode<E>>(
80        value: &mut T,
81        encoder: &mut E,
82        slot: Slot<'_, Self>,
83    ) -> Result<(), EncodeError> {
84        munge! {
85            let Self {
86                encoded: Encoded {
87                    mut maybe_num_bytes,
88                    mut num_handles,
89                    mut flags,
90                },
91            } = slot;
92        }
93
94        let handles_before = encoder.__internal_handle_count();
95
96        if size_of::<T::Encoded>() <= 4 {
97            let slot = unsafe { Slot::new_unchecked(maybe_num_bytes.as_mut_ptr().cast()) };
98            value.encode(encoder, slot)?;
99
100            **flags = Self::IS_INLINE_BIT;
101        } else {
102            let bytes_before = encoder.bytes_written();
103
104            encoder.encode_next(value)?;
105
106            **maybe_num_bytes = (encoder.bytes_written() - bytes_before).try_into().unwrap();
107            **flags = 0;
108        }
109
110        **num_handles = (encoder.__internal_handle_count() - handles_before).try_into().unwrap();
111
112        Ok(())
113    }
114
115    /// Returns the zero envelope.
116    #[inline]
117    pub fn zero() -> Self {
118        Self { zero: [0; 8] }
119    }
120
121    /// Returns whether a envelope slot is encoded as zero.
122    #[inline]
123    pub fn is_encoded_zero(slot: Slot<'_, Self>) -> bool {
124        munge!(let Self { zero } = slot);
125        *zero == [0; 8]
126    }
127
128    /// Returns whether an envelope is zero.
129    #[inline]
130    pub fn is_zero(&self) -> bool {
131        unsafe { self.zero == [0; 8] }
132    }
133
134    #[inline]
135    fn out_of_line_chunks(
136        maybe_num_bytes: Slot<'_, WireU32>,
137        flags: Slot<'_, WireU16>,
138    ) -> Result<Option<usize>, DecodeError> {
139        if **flags & Self::IS_INLINE_BIT == 0 {
140            let num_bytes = **maybe_num_bytes;
141            if num_bytes as usize % CHUNK_SIZE != 0 {
142                return Err(DecodeError::InvalidEnvelopeSize(num_bytes));
143            }
144            if num_bytes <= 4 {
145                return Err(DecodeError::OutOfLineValueTooSmall(num_bytes));
146            }
147            Ok(Some(num_bytes as usize / CHUNK_SIZE))
148        } else {
149            Ok(None)
150        }
151    }
152
153    /// Decodes and discards a static type in an envelope.
154    #[inline]
155    pub fn decode_unknown_static<D: InternalHandleDecoder + ?Sized>(
156        slot: Slot<'_, Self>,
157        decoder: &mut D,
158    ) -> Result<(), DecodeError> {
159        munge! {
160            let Self {
161                encoded: Encoded {
162                    maybe_num_bytes,
163                    num_handles,
164                    flags,
165                },
166            } = slot;
167        }
168
169        if let Some(count) = Self::out_of_line_chunks(maybe_num_bytes, flags)? {
170            return Err(DecodeError::ExpectedInline(count * CHUNK_SIZE));
171        }
172
173        decoder.__internal_take_handles(**num_handles as usize)?;
174
175        Ok(())
176    }
177
178    /// Decodes and discards an unknown value in an envelope.
179    #[inline]
180    pub fn decode_unknown<D: Decoder + ?Sized>(
181        slot: Slot<'_, Self>,
182        mut decoder: &mut D,
183    ) -> Result<(), DecodeError> {
184        munge! {
185            let Self {
186                encoded: Encoded {
187                    maybe_num_bytes,
188                    num_handles,
189                    flags,
190                },
191            } = slot;
192        }
193
194        if let Some(count) = Self::out_of_line_chunks(maybe_num_bytes, flags)? {
195            decoder.take_chunks(count)?;
196        }
197
198        decoder.__internal_take_handles(**num_handles as usize)?;
199
200        Ok(())
201    }
202
203    /// Decodes a value of a known type from an envelope.
204    #[inline]
205    pub fn decode_as_static<D: InternalHandleDecoder + ?Sized, T: Decode<D>>(
206        mut slot: Slot<'_, Self>,
207        decoder: &mut D,
208    ) -> Result<(), DecodeError> {
209        munge! {
210            let Self {
211                encoded: Encoded {
212                    maybe_num_bytes,
213                    num_handles,
214                    flags,
215                },
216             } = slot.as_mut();
217        }
218
219        let handles_before = decoder.__internal_handles_remaining();
220        let num_handles = **num_handles as usize;
221
222        if let Some(count) = Self::out_of_line_chunks(maybe_num_bytes, flags)? {
223            return Err(DecodeError::ExpectedInline(count * CHUNK_SIZE));
224        }
225
226        // Decode inline value
227        if size_of::<T>() > 4 {
228            return Err(DecodeError::InlineValueTooBig(size_of::<T>()));
229        }
230        munge!(let Self { mut decoded_inline } = slot);
231        let mut slot = unsafe { Slot::<T>::new_unchecked(decoded_inline.as_mut_ptr().cast()) };
232        T::decode(slot.as_mut(), decoder)?;
233
234        let handles_consumed = handles_before - decoder.__internal_handles_remaining();
235        if handles_consumed != num_handles {
236            return Err(DecodeError::IncorrectNumberOfHandlesConsumed {
237                expected: num_handles,
238                actual: handles_consumed,
239            });
240        }
241
242        Ok(())
243    }
244
245    /// Decodes a value of a known type from an envelope.
246    #[inline]
247    pub fn decode_as<D: Decoder + ?Sized, T: Decode<D>>(
248        mut slot: Slot<'_, Self>,
249        mut decoder: &mut D,
250    ) -> Result<(), DecodeError> {
251        munge! {
252            let Self {
253                encoded: Encoded {
254                    mut maybe_num_bytes,
255                    num_handles,
256                    flags,
257                },
258             } = slot.as_mut();
259        }
260
261        let handles_before = decoder.__internal_handles_remaining();
262        let num_handles = **num_handles as usize;
263
264        let out_of_line_chunks = Self::out_of_line_chunks(maybe_num_bytes.as_mut(), flags)?;
265        if let Some(_count) = out_of_line_chunks {
266            // Decode out-of-line value
267            // TODO: set cap on decoder to make sure that the envelope doesn't decode more bytes
268            // than it claims that it will
269            let mut value_slot = decoder.take_slot::<T>()?;
270            let value_ptr = value_slot.as_mut_ptr();
271            T::decode(value_slot, decoder)?;
272
273            munge!(let Self { mut decoded_out_of_line } = slot);
274            // SAFETY: Identical to `ptr.write(value_ptr.cast())`, but raw
275            // pointers don't currently implement `IntoBytes`.
276            unsafe { decoded_out_of_line.as_mut_ptr().write(value_ptr.cast()) };
277        } else {
278            // Decode inline value
279            if size_of::<T>() > 4 {
280                return Err(DecodeError::InlineValueTooBig(size_of::<T>()));
281            }
282            munge!(let Self { mut decoded_inline } = slot);
283            let mut slot = unsafe { Slot::<T>::new_unchecked(decoded_inline.as_mut_ptr().cast()) };
284            T::decode(slot.as_mut(), decoder)?;
285        }
286
287        let handles_consumed = handles_before - decoder.__internal_handles_remaining();
288        if handles_consumed != num_handles {
289            return Err(DecodeError::IncorrectNumberOfHandlesConsumed {
290                expected: num_handles,
291                actual: handles_consumed,
292            });
293        }
294
295        Ok(())
296    }
297
298    #[inline]
299    unsafe fn as_ptr<T>(this: *mut Self) -> *mut T {
300        if size_of::<T>() <= 4 {
301            let inline = unsafe { addr_of_mut!((*this).decoded_inline) };
302            inline.cast()
303        } else {
304            unsafe { (*this).decoded_out_of_line.cast() }
305        }
306    }
307
308    /// Returns a reference to the contained `T`.
309    ///
310    /// # Safety
311    ///
312    /// The envelope must have been successfully decoded as a `T`.
313    #[inline]
314    pub unsafe fn deref_unchecked<T>(&self) -> &T {
315        let ptr = unsafe { Self::as_ptr::<T>((self as *const Self).cast_mut()).cast_const() };
316        unsafe { &*ptr }
317    }
318
319    /// Clones the envelope, assuming that it contains an inline `T`.
320    ///
321    /// # Safety
322    ///
323    /// The envelope must have been successfully decoded as a `T`.
324    #[inline]
325    pub unsafe fn clone_unchecked<T: Clone>(&self) -> Self {
326        debug_assert_eq!(size_of::<T>(), 4);
327
328        union ClonedToDecodedInline<T> {
329            cloned: ManuallyDrop<T>,
330            decoded_inline: [MaybeUninit<u8>; 4],
331        }
332
333        let cloned = unsafe { self.deref_unchecked::<T>().clone() };
334        unsafe {
335            Self {
336                decoded_inline: ClonedToDecodedInline { cloned: ManuallyDrop::new(cloned) }
337                    .decoded_inline,
338            }
339        }
340    }
341}