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