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