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