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 zx::Handle;
9use zx::sys::{ZX_HANDLE_INVALID, zx_handle_t};
10
11use crate::fuchsia::{HandleDecoder, HandleEncoder};
12use crate::{
13    Constrained, Decode, DecodeError, Encodable, EncodableOption, Encode, EncodeError,
14    EncodeOption, FromWire, FromWireOption, IntoNatural, Slot, Unconstrained, Wire, WireU32, munge,
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(
68        mut slot: Slot<'_, Self>,
69        decoder: &mut D,
70        _constraint: <Self as Constrained>::Constraint,
71    ) -> Result<(), DecodeError> {
72        munge!(let Self { encoded } = slot.as_mut());
73
74        match **encoded {
75            0 => return Err(DecodeError::RequiredHandleAbsent),
76            u32::MAX => {
77                let handle = decoder.take_raw_handle()?;
78                munge!(let Self { mut decoded } = slot);
79                decoded.write(handle);
80            }
81            e => return Err(DecodeError::InvalidHandlePresence(e)),
82        }
83        Ok(())
84    }
85}
86
87impl Constrained for WireHandle {
88    type Constraint = ();
89
90    fn validate(
91        _slot: Slot<'_, Self>,
92        _constraint: Self::Constraint,
93    ) -> Result<(), crate::ValidationError> {
94        // TODO: validate handle rights.
95        Ok(())
96    }
97}
98
99/// An optional Zircon handle.
100#[derive(Debug)]
101#[repr(transparent)]
102pub struct WireOptionalHandle {
103    handle: WireHandle,
104}
105
106unsafe impl Wire for WireOptionalHandle {
107    type Decoded<'de> = Self;
108
109    #[inline]
110    fn zero_padding(out: &mut MaybeUninit<Self>) {
111        munge!(let Self { handle } = out);
112        WireHandle::zero_padding(handle);
113    }
114}
115
116impl WireOptionalHandle {
117    /// Encodes a handle as present in a slot.
118    pub fn set_encoded_present(out: &mut MaybeUninit<Self>) {
119        munge!(let Self { handle } = out);
120        WireHandle::set_encoded_present(handle);
121    }
122
123    /// Encodes a handle as absent in an output.
124    pub fn set_encoded_absent(out: &mut MaybeUninit<Self>) {
125        munge!(let Self { handle: WireHandle { encoded } } = out);
126        encoded.write(WireU32(ZX_HANDLE_INVALID));
127    }
128
129    /// Returns whether a handle is present.
130    pub fn is_some(&self) -> bool {
131        !self.handle.is_invalid()
132    }
133
134    /// Returns whether a handle is absent.
135    pub fn is_none(&self) -> bool {
136        self.handle.is_invalid()
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
146unsafe impl<D: HandleDecoder + ?Sized> Decode<D> for WireOptionalHandle {
147    fn decode(mut slot: Slot<'_, Self>, decoder: &mut D, _: ()) -> Result<(), DecodeError> {
148        munge!(let Self { handle: mut wire_handle } = slot.as_mut());
149        munge!(let WireHandle { encoded } = wire_handle.as_mut());
150
151        match **encoded {
152            0 => (),
153            u32::MAX => {
154                let handle = decoder.take_raw_handle()?;
155                munge!(let WireHandle { mut decoded } = wire_handle);
156                decoded.write(handle);
157            }
158            e => return Err(DecodeError::InvalidHandlePresence(e)),
159        }
160        Ok(())
161    }
162}
163
164impl Encodable for Handle {
165    type Encoded = WireHandle;
166}
167
168unsafe impl<E: HandleEncoder + ?Sized> Encode<E> for Handle {
169    fn encode(
170        self,
171        encoder: &mut E,
172        out: &mut MaybeUninit<Self::Encoded>,
173        _constraint: <Self::Encoded as Constrained>::Constraint,
174    ) -> Result<(), EncodeError> {
175        if self.is_invalid() {
176            Err(EncodeError::InvalidRequiredHandle)
177        } else {
178            encoder.push_handle(self)?;
179            WireHandle::set_encoded_present(out);
180            Ok(())
181        }
182    }
183}
184
185impl FromWire<WireHandle> for Handle {
186    fn from_wire(wire: WireHandle) -> Self {
187        // SAFETY: `WireHandle` is always a valid `Handle`.
188        let handle = unsafe { Handle::from_raw(wire.as_raw_handle()) };
189        forget(wire);
190        handle
191    }
192}
193
194impl IntoNatural for WireHandle {
195    type Natural = Handle;
196}
197
198impl EncodableOption for Handle {
199    type EncodedOption = WireOptionalHandle;
200}
201
202unsafe impl<E: HandleEncoder + ?Sized> EncodeOption<E> for Handle {
203    fn encode_option(
204        this: Option<Self>,
205        encoder: &mut E,
206        out: &mut MaybeUninit<Self::EncodedOption>,
207        _constraint: <Self::EncodedOption as Constrained>::Constraint,
208    ) -> Result<(), EncodeError> {
209        if let Some(handle) = this {
210            encoder.push_handle(handle)?;
211            WireOptionalHandle::set_encoded_present(out);
212        } else {
213            WireOptionalHandle::set_encoded_absent(out);
214        }
215        Ok(())
216    }
217}
218
219impl FromWireOption<WireOptionalHandle> for Handle {
220    fn from_wire_option(wire: WireOptionalHandle) -> Option<Self> {
221        let raw_handle = wire.as_raw_handle();
222        forget(wire);
223        raw_handle.map(|raw| unsafe { Handle::from_raw(raw) })
224    }
225}
226
227impl IntoNatural for WireOptionalHandle {
228    type Natural = Option<Handle>;
229}
230
231// TODO: validate handle rights
232impl Unconstrained for WireOptionalHandle {}