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