fidl_next_codec/fuchsia/
handle.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::cell::Cell;
6use core::fmt;
7use core::mem::{replace, ManuallyDrop};
8
9use zx::sys::{zx_handle_t, ZX_HANDLE_INVALID};
10use zx::{Handle, HandleBased as _};
11
12use crate::fuchsia::{HandleDecoder, HandleEncoder};
13use crate::{
14    munge, Decode, DecodeError, Encodable, EncodableOption, Encode, EncodeError, EncodeOption,
15    Slot, TakeFrom, WireU32, ZeroPadding,
16};
17
18/// A Zircon handle.
19#[repr(C, align(4))]
20pub union WireHandle {
21    encoded: WireU32,
22    decoded: ManuallyDrop<Cell<zx_handle_t>>,
23}
24
25impl Drop for WireHandle {
26    fn drop(&mut self) {
27        drop(self.take());
28    }
29}
30
31unsafe impl ZeroPadding for WireHandle {
32    #[inline]
33    unsafe fn zero_padding(_: *mut Self) {
34        // Wire handles have no padding
35    }
36}
37
38impl WireHandle {
39    /// Encodes a handle as present in a slot.
40    pub fn set_encoded_present(slot: Slot<'_, Self>) {
41        munge!(let Self { mut encoded } = slot);
42        *encoded = WireU32(u32::MAX);
43    }
44
45    /// Returns whether the underlying `zx_handle_t` is invalid.
46    pub fn is_invalid(&self) -> bool {
47        self.as_raw_handle() == ZX_HANDLE_INVALID
48    }
49
50    /// Takes the handle, if any, leaving an invalid handle in its place.
51    pub fn take(&self) -> Handle {
52        let raw = unsafe { self.decoded.replace(ZX_HANDLE_INVALID) };
53        unsafe { Handle::from_raw(raw) }
54    }
55
56    /// Returns the underlying [`zx_handle_t`].
57    #[inline]
58    pub fn as_raw_handle(&self) -> zx_handle_t {
59        unsafe { self.decoded.get() }
60    }
61}
62
63impl fmt::Debug for WireHandle {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        self.as_raw_handle().fmt(f)
66    }
67}
68
69unsafe impl<D: HandleDecoder + ?Sized> Decode<D> for WireHandle {
70    fn decode(mut slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
71        munge!(let Self { encoded } = slot.as_mut());
72
73        match **encoded {
74            0 => (),
75            u32::MAX => {
76                let handle = decoder.take_handle()?;
77                munge!(let Self { mut decoded } = slot);
78                // SAFETY: `Cell` has no uninit bytes, even though it doesn't implement `IntoBytes`.
79                unsafe {
80                    decoded.as_mut_ptr().write(ManuallyDrop::new(Cell::new(handle.into_raw())));
81                }
82            }
83            e => return Err(DecodeError::InvalidHandlePresence(e)),
84        }
85        Ok(())
86    }
87}
88
89impl TakeFrom<WireHandle> for Handle {
90    fn take_from(from: &WireHandle) -> Self {
91        from.take()
92    }
93}
94
95/// An optional Zircon handle.
96#[derive(Debug)]
97#[repr(transparent)]
98pub struct WireOptionalHandle {
99    handle: WireHandle,
100}
101
102unsafe impl ZeroPadding for WireOptionalHandle {
103    #[inline]
104    unsafe fn zero_padding(ptr: *mut Self) {
105        unsafe {
106            WireHandle::zero_padding(ptr.cast());
107        }
108    }
109}
110
111impl WireOptionalHandle {
112    /// Encodes a handle as present in a slot.
113    pub fn set_encoded_present(slot: Slot<'_, Self>) {
114        munge!(let Self { handle } = slot);
115        WireHandle::set_encoded_present(handle);
116    }
117
118    /// Encodes a handle as absent in a slot.
119    pub fn set_encoded_absent(slot: Slot<'_, Self>) {
120        munge!(let Self { handle: WireHandle { mut encoded } } = slot);
121        *encoded = WireU32(ZX_HANDLE_INVALID);
122    }
123
124    /// Returns whether a handle is present.
125    pub fn is_some(&self) -> bool {
126        !self.handle.is_invalid()
127    }
128
129    /// Returns whether a handle is absent.
130    pub fn is_none(&self) -> bool {
131        self.handle.is_invalid()
132    }
133
134    /// Takes the handle, if any, leaving an invalid handle in its place.
135    pub fn take(&self) -> Option<Handle> {
136        self.is_some().then(|| self.handle.take())
137    }
138
139    /// Returns the underlying [`zx_handle_t`], if any.
140    #[inline]
141    pub fn as_raw_handle(&self) -> Option<zx_handle_t> {
142        self.is_some().then(|| self.handle.as_raw_handle())
143    }
144}
145
146impl Encodable for Handle {
147    type Encoded = WireHandle;
148}
149
150impl<E: HandleEncoder + ?Sized> Encode<E> for Handle {
151    fn encode(
152        &mut self,
153        encoder: &mut E,
154        slot: Slot<'_, Self::Encoded>,
155    ) -> Result<(), EncodeError> {
156        if self.is_invalid() {
157            Err(EncodeError::InvalidRequiredHandle)
158        } else {
159            let handle = replace(self, Handle::invalid());
160            encoder.push_handle(handle)?;
161            WireHandle::set_encoded_present(slot);
162            Ok(())
163        }
164    }
165}
166
167impl EncodableOption for Handle {
168    type EncodedOption = WireOptionalHandle;
169}
170
171impl<E: HandleEncoder + ?Sized> EncodeOption<E> for Handle {
172    fn encode_option(
173        this: Option<&mut Self>,
174        encoder: &mut E,
175        slot: Slot<'_, Self::EncodedOption>,
176    ) -> Result<(), EncodeError> {
177        if let Some(handle) = this {
178            let handle = replace(handle, Handle::invalid());
179            encoder.push_handle(handle)?;
180            WireOptionalHandle::set_encoded_present(slot);
181        } else {
182            WireOptionalHandle::set_encoded_absent(slot);
183        }
184        Ok(())
185    }
186}
187
188unsafe impl<D: HandleDecoder + ?Sized> Decode<D> for WireOptionalHandle {
189    fn decode(mut slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
190        munge!(let Self { handle } = slot.as_mut());
191        WireHandle::decode(handle, decoder)
192    }
193}
194
195impl TakeFrom<WireOptionalHandle> for Option<Handle> {
196    fn take_from(from: &WireOptionalHandle) -> Self {
197        from.take()
198    }
199}