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