fidl_next_codec/wire/
table.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::MaybeUninit;
6
7use munge::munge;
8
9use crate::{
10    DecodeError, Decoder, DecoderExt as _, Slot, Wire, WireEnvelope, WirePointer, WireU64,
11};
12
13/// A FIDL table
14#[repr(C)]
15pub struct WireTable<'de> {
16    len: WireU64,
17    ptr: WirePointer<'de, WireEnvelope>,
18}
19
20unsafe impl Wire for WireTable<'static> {
21    type Decoded<'de> = WireTable<'de>;
22
23    #[inline]
24    fn zero_padding(_: &mut MaybeUninit<Self>) {
25        // Wire tables have no padding
26    }
27}
28
29impl WireTable<'static> {
30    /// Encodes that a table contains `len` values in a slot.
31    #[inline]
32    pub fn encode_len(out: &mut MaybeUninit<Self>, len: usize) {
33        munge!(let Self { len: table_len, ptr } = out);
34        table_len.write(WireU64(len.try_into().unwrap()));
35        WirePointer::encode_present(ptr);
36    }
37
38    /// Decodes the fields of the table with a decoding function.
39    ///
40    /// The decoding function receives the ordinal of the field, its slot, and the decoder.
41    #[inline]
42    pub fn decode_with<D: Decoder + ?Sized>(
43        slot: Slot<'_, Self>,
44        mut decoder: &mut D,
45        f: impl Fn(i64, Slot<'_, WireEnvelope>, &mut D) -> Result<(), DecodeError>,
46    ) -> Result<(), DecodeError> {
47        munge!(let Self { len, mut ptr } = slot);
48
49        if WirePointer::is_encoded_present(ptr.as_mut())? {
50            let mut envelopes = decoder.take_slice_slot::<WireEnvelope>(**len as usize)?;
51            let envelopes_ptr = envelopes.as_mut_ptr().cast::<WireEnvelope>();
52
53            for i in 0..**len as usize {
54                let mut envelope = envelopes.index(i);
55                if !WireEnvelope::is_encoded_zero(envelope.as_mut()) {
56                    f((i + 1) as i64, envelope, decoder)?;
57                }
58            }
59
60            WirePointer::set_decoded(ptr, envelopes_ptr);
61        } else if **len != 0 {
62            return Err(DecodeError::InvalidOptionalSize(**len));
63        }
64
65        Ok(())
66    }
67}
68
69impl WireTable<'_> {
70    /// Returns a reference to the envelope for the given ordinal, if any.
71    #[inline]
72    pub fn get(&self, ordinal: usize) -> Option<&WireEnvelope> {
73        if ordinal == 0 || ordinal > *self.len as usize {
74            return None;
75        }
76
77        let envelope = unsafe { &*self.ptr.as_ptr().add(ordinal - 1) };
78        (!envelope.is_zero()).then_some(envelope)
79    }
80}