fidl_next_codec/wire/
boxed.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::fmt;
6use core::mem::{MaybeUninit, forget};
7use core::ptr::NonNull;
8
9use munge::munge;
10
11use crate::{
12    Decode, DecodeError, Decoder, DecoderExt as _, Encodable, EncodableOption, Encode, EncodeError,
13    EncodeOption, EncodeOptionRef, EncodeRef, FromWire, FromWireOption, FromWireOptionRef,
14    FromWireRef, Slot, Wire, WirePointer,
15};
16
17/// A boxed (optional) FIDL value.
18#[repr(C)]
19pub struct WireBox<'de, T> {
20    ptr: WirePointer<'de, T>,
21}
22
23// SAFETY: `WireBox` doesn't add any restrictions on sending across thread boundaries, and so is
24// `Send` if `T` is `Send`.
25unsafe impl<T: Send> Send for WireBox<'_, T> {}
26
27// SAFETY: `WireBox` doesn't add any interior mutability, so it is `Sync` if `T` is `Sync`.
28unsafe impl<T: Sync> Sync for WireBox<'_, T> {}
29
30impl<T> Drop for WireBox<'_, T> {
31    fn drop(&mut self) {
32        if self.is_some() {
33            unsafe {
34                self.ptr.as_ptr().drop_in_place();
35            }
36        }
37    }
38}
39
40unsafe impl<T: Wire> Wire for WireBox<'static, T> {
41    type Decoded<'de> = WireBox<'de, T::Decoded<'de>>;
42
43    #[inline]
44    fn zero_padding(_: &mut MaybeUninit<Self>) {
45        // Wire boxes have no padding
46    }
47}
48
49impl<T> WireBox<'_, T> {
50    /// Encodes that a value is present in an output.
51    pub fn encode_present(out: &mut MaybeUninit<Self>) {
52        munge!(let Self { ptr } = out);
53        WirePointer::encode_present(ptr);
54    }
55
56    /// Encodes that a value is absent in a slot.
57    pub fn encode_absent(out: &mut MaybeUninit<Self>) {
58        munge!(let Self { ptr } = out);
59        WirePointer::encode_absent(ptr);
60    }
61
62    /// Returns whether the value is present.
63    pub fn is_some(&self) -> bool {
64        !self.ptr.as_ptr().is_null()
65    }
66
67    /// Returns whether the value is absent.
68    pub fn is_none(&self) -> bool {
69        !self.is_some()
70    }
71
72    /// Returns a reference to the boxed value, if any.
73    pub fn as_ref(&self) -> Option<&T> {
74        NonNull::new(self.ptr.as_ptr()).map(|ptr| unsafe { ptr.as_ref() })
75    }
76
77    /// Returns an `Owned` of the boxed value, if any.
78    pub fn into_option(self) -> Option<T> {
79        let ptr = self.ptr.as_ptr();
80        forget(self);
81        if ptr.is_null() { None } else { unsafe { Some(ptr.read()) } }
82    }
83}
84
85impl<T: fmt::Debug> fmt::Debug for WireBox<'_, T> {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        self.as_ref().fmt(f)
88    }
89}
90
91unsafe impl<D: Decoder + ?Sized, T: Decode<D>> Decode<D> for WireBox<'static, T> {
92    fn decode(slot: Slot<'_, Self>, mut decoder: &mut D) -> Result<(), DecodeError> {
93        munge!(let Self { mut ptr } = slot);
94
95        if WirePointer::is_encoded_present(ptr.as_mut())? {
96            let mut value = decoder.take_slot::<T>()?;
97            T::decode(value.as_mut(), decoder)?;
98            WirePointer::set_decoded(ptr, value.as_mut_ptr());
99        }
100
101        Ok(())
102    }
103}
104
105impl<T: EncodableOption> Encodable for Option<T> {
106    type Encoded = T::EncodedOption;
107}
108
109unsafe impl<E: ?Sized, T: EncodeOption<E>> Encode<E> for Option<T> {
110    fn encode(
111        self,
112        encoder: &mut E,
113        out: &mut MaybeUninit<Self::Encoded>,
114    ) -> Result<(), EncodeError> {
115        T::encode_option(self, encoder, out)
116    }
117}
118
119unsafe impl<E: ?Sized, T: EncodeOptionRef<E>> EncodeRef<E> for Option<T> {
120    fn encode_ref(
121        &self,
122        encoder: &mut E,
123        out: &mut MaybeUninit<Self::Encoded>,
124    ) -> Result<(), EncodeError> {
125        T::encode_option_ref(self.as_ref(), encoder, out)
126    }
127}
128
129impl<T: FromWire<W>, W> FromWireOption<WireBox<'_, W>> for T {
130    fn from_wire_option(wire: WireBox<'_, W>) -> Option<Self> {
131        wire.into_option().map(T::from_wire)
132    }
133}
134
135impl<T: FromWireRef<W>, W> FromWireOptionRef<WireBox<'_, W>> for T {
136    fn from_wire_option_ref(wire: &WireBox<'_, W>) -> Option<Self> {
137        wire.as_ref().map(T::from_wire_ref)
138    }
139}