Skip to main content

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