fidl_next_codec/wire/vec/
optional.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::{needs_drop, MaybeUninit};
6use core::{fmt, slice};
7
8use munge::munge;
9
10use super::raw::RawWireVector;
11use crate::{
12    Decode, DecodeError, Decoder, DecoderExt as _, Encodable, EncodableOption, Encode, EncodeError,
13    EncodeOption, EncodeOptionRef, EncodeRef, Encoder, EncoderExt as _, Slot, TakeFrom,
14    WirePointer, WireVector, ZeroPadding,
15};
16
17/// An optional FIDL vector
18#[repr(transparent)]
19pub struct WireOptionalVector<T> {
20    raw: RawWireVector<T>,
21}
22
23unsafe impl<T> ZeroPadding for WireOptionalVector<T> {
24    #[inline]
25    fn zero_padding(out: &mut MaybeUninit<Self>) {
26        munge!(let Self { raw } = out);
27        RawWireVector::<T>::zero_padding(raw);
28    }
29}
30
31impl<T> Drop for WireOptionalVector<T> {
32    fn drop(&mut self) {
33        if needs_drop::<T>() && self.is_some() {
34            unsafe {
35                self.raw.as_slice_ptr().drop_in_place();
36            }
37        }
38    }
39}
40
41impl<T> WireOptionalVector<T> {
42    /// Encodes that a vector is present in a slot.
43    pub fn encode_present(out: &mut MaybeUninit<Self>, len: u64) {
44        munge!(let Self { raw } = out);
45        RawWireVector::encode_present(raw, len);
46    }
47
48    /// Encodes that a vector is absent in a slot.
49    pub fn encode_absent(out: &mut MaybeUninit<Self>) {
50        munge!(let Self { raw } = out);
51        RawWireVector::encode_absent(raw);
52    }
53
54    /// Returns whether the vector is present.
55    pub fn is_some(&self) -> bool {
56        !self.raw.as_ptr().is_null()
57    }
58
59    /// Returns whether the vector is absent.
60    pub fn is_none(&self) -> bool {
61        !self.is_some()
62    }
63
64    /// Gets a reference to the vector, if any.
65    pub fn as_ref(&self) -> Option<&WireVector<T>> {
66        if self.is_some() {
67            Some(unsafe { &*(self as *const Self).cast() })
68        } else {
69            None
70        }
71    }
72
73    /// Decodes a wire vector which contains raw data.
74    ///
75    /// # Safety
76    ///
77    /// The elements of the wire vecot rmust not need to be individually decoded, and must always be
78    /// valid.
79    pub unsafe fn decode_raw<D>(
80        mut slot: Slot<'_, Self>,
81        mut decoder: &mut D,
82    ) -> Result<(), DecodeError>
83    where
84        D: Decoder + ?Sized,
85        T: Decode<D>,
86    {
87        munge!(let Self { raw: RawWireVector { len, mut ptr } } = slot.as_mut());
88
89        if WirePointer::is_encoded_present(ptr.as_mut())? {
90            let mut slice = decoder.take_slice_slot::<T>(**len as usize)?;
91            WirePointer::set_decoded(ptr, slice.as_mut_ptr().cast());
92        } else if *len != 0 {
93            return Err(DecodeError::InvalidOptionalSize(**len));
94        }
95
96        Ok(())
97    }
98}
99
100impl<T: fmt::Debug> fmt::Debug for WireOptionalVector<T> {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        self.as_ref().fmt(f)
103    }
104}
105
106unsafe impl<D: Decoder + ?Sized, T: Decode<D>> Decode<D> for WireOptionalVector<T> {
107    fn decode(mut slot: Slot<'_, Self>, mut decoder: &mut D) -> Result<(), DecodeError> {
108        munge!(let Self { raw: RawWireVector { len, mut ptr } } = slot.as_mut());
109
110        if WirePointer::is_encoded_present(ptr.as_mut())? {
111            let mut slice = decoder.take_slice_slot::<T>(**len as usize)?;
112            for i in 0..**len as usize {
113                T::decode(slice.index(i), decoder)?;
114            }
115            WirePointer::set_decoded(ptr, slice.as_mut_ptr().cast());
116        } else if *len != 0 {
117            return Err(DecodeError::InvalidOptionalSize(**len));
118        }
119
120        Ok(())
121    }
122}
123
124#[inline]
125fn encode_to_optional_vector<V, E, T>(
126    value: Option<V>,
127    encoder: &mut E,
128    out: &mut MaybeUninit<WireOptionalVector<T::Encoded>>,
129) -> Result<(), EncodeError>
130where
131    V: AsRef<[T]> + IntoIterator,
132    V::IntoIter: ExactSizeIterator,
133    V::Item: Encode<E, Encoded = T::Encoded>,
134    E: Encoder + ?Sized,
135    T: Encode<E>,
136{
137    if let Some(value) = value {
138        let len = value.as_ref().len();
139        if T::COPY_OPTIMIZATION.is_enabled() {
140            let slice = value.as_ref();
141            // SAFETY: `T` has copy optimization enabled, which guarantees that it has no uninit
142            // bytes and can be copied directly to the output instead of calling `encode`. This
143            // means that we may cast `&[T]` to `&[u8]` and write those bytes.
144            let bytes = unsafe { slice::from_raw_parts(slice.as_ptr().cast(), size_of_val(slice)) };
145            encoder.write(bytes);
146        } else {
147            encoder.encode_next_iter(value.into_iter())?;
148        }
149        WireOptionalVector::encode_present(out, len as u64);
150    } else {
151        WireOptionalVector::encode_absent(out);
152    }
153    Ok(())
154}
155
156impl<T: Encodable> EncodableOption for Vec<T> {
157    type EncodedOption = WireOptionalVector<T::Encoded>;
158}
159
160unsafe impl<E: Encoder + ?Sized, T: Encode<E>> EncodeOption<E> for Vec<T> {
161    fn encode_option(
162        this: Option<Self>,
163        encoder: &mut E,
164        out: &mut MaybeUninit<Self::EncodedOption>,
165    ) -> Result<(), EncodeError> {
166        encode_to_optional_vector(this, encoder, out)
167    }
168}
169
170unsafe impl<E: Encoder + ?Sized, T: EncodeRef<E>> EncodeOptionRef<E> for Vec<T> {
171    fn encode_option_ref(
172        this: Option<&Self>,
173        encoder: &mut E,
174        out: &mut MaybeUninit<Self::EncodedOption>,
175    ) -> Result<(), EncodeError> {
176        encode_to_optional_vector(this, encoder, out)
177    }
178}
179
180impl<T: Encodable> EncodableOption for &[T] {
181    type EncodedOption = WireOptionalVector<T::Encoded>;
182}
183
184unsafe impl<E: Encoder + ?Sized, T: EncodeRef<E>> EncodeOption<E> for &[T] {
185    fn encode_option(
186        this: Option<Self>,
187        encoder: &mut E,
188        out: &mut MaybeUninit<Self::EncodedOption>,
189    ) -> Result<(), EncodeError> {
190        encode_to_optional_vector(this, encoder, out)
191    }
192}
193
194impl<T: TakeFrom<WT>, WT> TakeFrom<WireOptionalVector<WT>> for Option<Vec<T>> {
195    fn take_from(from: &WireOptionalVector<WT>) -> Self {
196        from.as_ref().map(Vec::take_from)
197    }
198}