Skip to main content

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