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