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::{forget, MaybeUninit};
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() {
82            None
83        } else {
84            unsafe { Some(ptr.read()) }
85        }
86    }
87}
88
89impl<T: fmt::Debug> fmt::Debug for WireBox<'_, T> {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        self.as_ref().fmt(f)
92    }
93}
94
95unsafe impl<D: Decoder + ?Sized, T: Decode<D>> Decode<D> for WireBox<'static, T> {
96    fn decode(slot: Slot<'_, Self>, mut decoder: &mut D) -> Result<(), DecodeError> {
97        munge!(let Self { mut ptr } = slot);
98
99        if WirePointer::is_encoded_present(ptr.as_mut())? {
100            let mut value = decoder.take_slot::<T>()?;
101            T::decode(value.as_mut(), decoder)?;
102            WirePointer::set_decoded(ptr, value.as_mut_ptr());
103        }
104
105        Ok(())
106    }
107}
108
109impl<T: EncodableOption> Encodable for Option<T> {
110    type Encoded = T::EncodedOption;
111}
112
113unsafe impl<E: ?Sized, T: EncodeOption<E>> Encode<E> for Option<T> {
114    fn encode(
115        self,
116        encoder: &mut E,
117        out: &mut MaybeUninit<Self::Encoded>,
118    ) -> Result<(), EncodeError> {
119        T::encode_option(self, encoder, out)
120    }
121}
122
123unsafe impl<E: ?Sized, T: EncodeOptionRef<E>> EncodeRef<E> for Option<T> {
124    fn encode_ref(
125        &self,
126        encoder: &mut E,
127        out: &mut MaybeUninit<Self::Encoded>,
128    ) -> Result<(), EncodeError> {
129        T::encode_option_ref(self.as_ref(), encoder, out)
130    }
131}
132
133impl<T: FromWire<W>, W> FromWireOption<WireBox<'_, W>> for T {
134    fn from_wire_option(wire: WireBox<'_, W>) -> Option<Self> {
135        wire.into_option().map(T::from_wire)
136    }
137}
138
139impl<T: FromWireRef<W>, W> FromWireOptionRef<WireBox<'_, W>> for T {
140    fn from_wire_option_ref(wire: &WireBox<'_, W>) -> Option<Self> {
141        wire.as_ref().map(T::from_wire_ref)
142    }
143}