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