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