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::fmt;
6use core::mem::{forget, MaybeUninit};
7
8use zx::sys::{zx_handle_t, ZX_HANDLE_INVALID};
9use zx::Handle;
10
11use crate::fuchsia::{HandleDecoder, HandleEncoder};
12use crate::{
13    munge, Decode, DecodeError, Encodable, EncodableOption, Encode, EncodeError, EncodeOption,
14    FromWire, FromWireOption, Slot, Wire, WireU32,
15};
16
17/// A Zircon handle.
18#[repr(C, align(4))]
19pub union WireHandle {
20    encoded: WireU32,
21    decoded: zx_handle_t,
22}
23
24impl Drop for WireHandle {
25    fn drop(&mut self) {
26        // SAFETY: `WireHandle` is always a valid `Handle`.
27        let handle = unsafe { Handle::from_raw(self.as_raw_handle()) };
28        drop(handle);
29    }
30}
31
32unsafe impl Wire for WireHandle {
33    type Decoded<'de> = Self;
34
35    #[inline]
36    fn zero_padding(_: &mut MaybeUninit<Self>) {
37        // Wire handles have no padding
38    }
39}
40
41impl WireHandle {
42    /// Encodes a handle as present in an output.
43    pub fn set_encoded_present(out: &mut MaybeUninit<Self>) {
44        munge!(let Self { encoded } = out);
45        encoded.write(WireU32(u32::MAX));
46    }
47
48    /// Returns whether the underlying `zx_handle_t` is invalid.
49    pub fn is_invalid(&self) -> bool {
50        self.as_raw_handle() == ZX_HANDLE_INVALID
51    }
52
53    /// Returns the underlying [`zx_handle_t`].
54    #[inline]
55    pub fn as_raw_handle(&self) -> zx_handle_t {
56        unsafe { self.decoded }
57    }
58}
59
60impl fmt::Debug for WireHandle {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        self.as_raw_handle().fmt(f)
63    }
64}
65
66unsafe impl<D: HandleDecoder + ?Sized> Decode<D> for WireHandle {
67    fn decode(mut slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
68        munge!(let Self { encoded } = slot.as_mut());
69
70        match **encoded {
71            0 => (),
72            u32::MAX => {
73                let handle = decoder.take_raw_handle()?;
74                munge!(let Self { mut decoded } = slot);
75                // SAFETY: `Cell` has no uninit bytes, even though it doesn't implement `IntoBytes`.
76                unsafe {
77                    decoded.as_mut_ptr().write(handle);
78                }
79            }
80            e => return Err(DecodeError::InvalidHandlePresence(e)),
81        }
82        Ok(())
83    }
84}
85
86/// An optional Zircon handle.
87#[derive(Debug)]
88#[repr(transparent)]
89pub struct WireOptionalHandle {
90    handle: WireHandle,
91}
92
93unsafe impl Wire for WireOptionalHandle {
94    type Decoded<'de> = Self;
95
96    #[inline]
97    fn zero_padding(out: &mut MaybeUninit<Self>) {
98        munge!(let Self { handle } = out);
99        WireHandle::zero_padding(handle);
100    }
101}
102
103impl WireOptionalHandle {
104    /// Encodes a handle as present in a slot.
105    pub fn set_encoded_present(out: &mut MaybeUninit<Self>) {
106        munge!(let Self { handle } = out);
107        WireHandle::set_encoded_present(handle);
108    }
109
110    /// Encodes a handle as absent in an output.
111    pub fn set_encoded_absent(out: &mut MaybeUninit<Self>) {
112        munge!(let Self { handle: WireHandle { encoded } } = out);
113        encoded.write(WireU32(ZX_HANDLE_INVALID));
114    }
115
116    /// Returns whether a handle is present.
117    pub fn is_some(&self) -> bool {
118        !self.handle.is_invalid()
119    }
120
121    /// Returns whether a handle is absent.
122    pub fn is_none(&self) -> bool {
123        self.handle.is_invalid()
124    }
125
126    /// Returns the underlying [`zx_handle_t`], if any.
127    #[inline]
128    pub fn as_raw_handle(&self) -> Option<zx_handle_t> {
129        self.is_some().then(|| self.handle.as_raw_handle())
130    }
131}
132
133unsafe impl<D: HandleDecoder + ?Sized> Decode<D> for WireOptionalHandle {
134    fn decode(mut slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
135        munge!(let Self { handle } = slot.as_mut());
136        WireHandle::decode(handle, decoder)
137    }
138}
139
140impl Encodable for Handle {
141    type Encoded = WireHandle;
142}
143
144unsafe impl<E: HandleEncoder + ?Sized> Encode<E> for Handle {
145    fn encode(
146        self,
147        encoder: &mut E,
148        out: &mut MaybeUninit<Self::Encoded>,
149    ) -> Result<(), EncodeError> {
150        if self.is_invalid() {
151            Err(EncodeError::InvalidRequiredHandle)
152        } else {
153            encoder.push_handle(self)?;
154            WireHandle::set_encoded_present(out);
155            Ok(())
156        }
157    }
158}
159
160impl FromWire<WireHandle> for Handle {
161    fn from_wire(wire: WireHandle) -> Self {
162        // SAFETY: `WireHandle` is always a valid `Handle`.
163        let handle = unsafe { Handle::from_raw(wire.as_raw_handle()) };
164        forget(wire);
165        handle
166    }
167}
168
169impl EncodableOption for Handle {
170    type EncodedOption = WireOptionalHandle;
171}
172
173unsafe impl<E: HandleEncoder + ?Sized> EncodeOption<E> for Handle {
174    fn encode_option(
175        this: Option<Self>,
176        encoder: &mut E,
177        out: &mut MaybeUninit<Self::EncodedOption>,
178    ) -> Result<(), EncodeError> {
179        if let Some(handle) = this {
180            encoder.push_handle(handle)?;
181            WireOptionalHandle::set_encoded_present(out);
182        } else {
183            WireOptionalHandle::set_encoded_absent(out);
184        }
185        Ok(())
186    }
187}
188
189impl FromWireOption<WireOptionalHandle> for Handle {
190    fn from_wire_option(wire: WireOptionalHandle) -> Option<Self> {
191        let raw_handle = wire.as_raw_handle();
192        forget(wire);
193        raw_handle.map(|raw| unsafe { Handle::from_raw(raw) })
194    }
195}
196
197// TODO: newtype handle subtypes
198macro_rules! impl_takefrom {
199    ($($name:ident),* $(,)?) => {
200        $(
201            impl FromWire<WireHandle> for zx::$name {
202                fn from_wire(wire: WireHandle) -> Self {
203                    Handle::from_wire(wire).into()
204                }
205            }
206
207            impl FromWireOption<WireOptionalHandle> for zx::$name {
208                fn from_wire_option(wire: WireOptionalHandle) -> Option<Self> {
209                    Handle::from_wire_option(wire).map(<zx::$name>::from)
210                }
211            }
212        )*
213    }
214}
215
216impl_takefrom! {
217    Process,
218    Thread,
219    Vmo,
220    Channel,
221    Event,
222    Port,
223    Interrupt,
224    Socket,
225    Resource,
226    EventPair,
227    Job,
228    Vmar,
229    Fifo,
230    Guest,
231    Vcpu,
232    Timer,
233    Iommu,
234    Bti,
235    Profile,
236    Pmt,
237    Pager,
238    Exception,
239    Clock,
240    Stream,
241    Iob,
242}