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    Decode, DecodeError, Encodable, EncodableOption, Encode, EncodeError, EncodeOption, FromWire,
14    FromWireOption, Slot, 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(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                decoded.write(handle);
76            }
77            e => return Err(DecodeError::InvalidHandlePresence(e)),
78        }
79        Ok(())
80    }
81}
82
83/// An optional Zircon handle.
84#[derive(Debug)]
85#[repr(transparent)]
86pub struct WireOptionalHandle {
87    handle: WireHandle,
88}
89
90unsafe impl Wire for WireOptionalHandle {
91    type Decoded<'de> = Self;
92
93    #[inline]
94    fn zero_padding(out: &mut MaybeUninit<Self>) {
95        munge!(let Self { handle } = out);
96        WireHandle::zero_padding(handle);
97    }
98}
99
100impl WireOptionalHandle {
101    /// Encodes a handle as present in a slot.
102    pub fn set_encoded_present(out: &mut MaybeUninit<Self>) {
103        munge!(let Self { handle } = out);
104        WireHandle::set_encoded_present(handle);
105    }
106
107    /// Encodes a handle as absent in an output.
108    pub fn set_encoded_absent(out: &mut MaybeUninit<Self>) {
109        munge!(let Self { handle: WireHandle { encoded } } = out);
110        encoded.write(WireU32(ZX_HANDLE_INVALID));
111    }
112
113    /// Returns whether a handle is present.
114    pub fn is_some(&self) -> bool {
115        !self.handle.is_invalid()
116    }
117
118    /// Returns whether a handle is absent.
119    pub fn is_none(&self) -> bool {
120        self.handle.is_invalid()
121    }
122
123    /// Returns the underlying [`zx_handle_t`], if any.
124    #[inline]
125    pub fn as_raw_handle(&self) -> Option<zx_handle_t> {
126        self.is_some().then(|| self.handle.as_raw_handle())
127    }
128}
129
130unsafe impl<D: HandleDecoder + ?Sized> Decode<D> for WireOptionalHandle {
131    fn decode(mut slot: Slot<'_, Self>, decoder: &mut D) -> Result<(), DecodeError> {
132        munge!(let Self { handle } = slot.as_mut());
133        WireHandle::decode(handle, decoder)
134    }
135}
136
137impl Encodable for Handle {
138    type Encoded = WireHandle;
139}
140
141unsafe impl<E: HandleEncoder + ?Sized> Encode<E> for Handle {
142    fn encode(
143        self,
144        encoder: &mut E,
145        out: &mut MaybeUninit<Self::Encoded>,
146    ) -> Result<(), EncodeError> {
147        if self.is_invalid() {
148            Err(EncodeError::InvalidRequiredHandle)
149        } else {
150            encoder.push_handle(self)?;
151            WireHandle::set_encoded_present(out);
152            Ok(())
153        }
154    }
155}
156
157impl FromWire<WireHandle> for Handle {
158    fn from_wire(wire: WireHandle) -> Self {
159        // SAFETY: `WireHandle` is always a valid `Handle`.
160        let handle = unsafe { Handle::from_raw(wire.as_raw_handle()) };
161        forget(wire);
162        handle
163    }
164}
165
166impl EncodableOption for Handle {
167    type EncodedOption = WireOptionalHandle;
168}
169
170unsafe impl<E: HandleEncoder + ?Sized> EncodeOption<E> for Handle {
171    fn encode_option(
172        this: Option<Self>,
173        encoder: &mut E,
174        out: &mut MaybeUninit<Self::EncodedOption>,
175    ) -> Result<(), EncodeError> {
176        if let Some(handle) = this {
177            encoder.push_handle(handle)?;
178            WireOptionalHandle::set_encoded_present(out);
179        } else {
180            WireOptionalHandle::set_encoded_absent(out);
181        }
182        Ok(())
183    }
184}
185
186impl FromWireOption<WireOptionalHandle> for Handle {
187    fn from_wire_option(wire: WireOptionalHandle) -> Option<Self> {
188        let raw_handle = wire.as_raw_handle();
189        forget(wire);
190        raw_handle.map(|raw| unsafe { Handle::from_raw(raw) })
191    }
192}