fdf_fidl/
wire.rs

1// Copyright 2025 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
5//! Driver-specific extensions to FIDL.
6
7use core::fmt;
8use core::mem::{MaybeUninit, forget};
9use core::num::NonZero;
10
11use fdf_channel::channel::Channel;
12use fdf_core::handle::{DriverHandle, fdf_handle_t};
13use fidl_next::fuchsia::{HandleDecoder, HandleEncoder};
14use fidl_next::{
15    Constrained, Decode, DecodeError, Encode, EncodeError, EncodeOption, FromWire, FromWireOption,
16    IntoNatural, Slot, Unconstrained, Wire, WireU32, munge,
17};
18
19use crate::DriverChannel;
20
21/// The FIDL wire type for [`DriverChannel`].
22///
23/// This type follows the FIDL wire format for handles, and is separate from the
24/// Zircon handle wire type. This ensures that we never confuse the two types
25/// when using FIDL.
26#[repr(C, align(4))]
27pub union WireDriverChannel {
28    encoded: WireU32,
29    decoded: fdf_handle_t,
30}
31
32impl Drop for WireDriverChannel {
33    fn drop(&mut self) {
34        // SAFETY: `WireDriverHandle` is always non-zero.
35        let raw_handle = unsafe { NonZero::new_unchecked(self.as_raw_handle()) };
36        // SAFETY: `WireDriverHandle` is always a valid `DriverHandle`.
37        let handle = unsafe { DriverHandle::new_unchecked(raw_handle) };
38        drop(handle);
39    }
40}
41
42// SAFETY:
43// - `WireDriverHandle` doesn't reference any other decoded data.
44// - `WireDriverHandle` does not have any padding bytes.
45unsafe impl Wire for WireDriverChannel {
46    type Decoded<'de> = Self;
47
48    #[inline]
49    fn zero_padding(_: &mut MaybeUninit<Self>) {
50        // Wire driver handles have no padding
51    }
52}
53
54impl WireDriverChannel {
55    /// Encodes a driver handle as present in an output.
56    pub fn set_encoded_present(out: &mut MaybeUninit<Self>) {
57        munge!(let Self { encoded } = out);
58        encoded.write(WireU32(u32::MAX));
59    }
60
61    /// Returns the underlying [`fdf_handle_t`].
62    #[inline]
63    pub fn as_raw_handle(&self) -> fdf_handle_t {
64        // SAFETY: If we have a reference to `WireDriverHandle`, then it has
65        // been successfully decoded and the `decoded` field is safe to read.
66        unsafe { self.decoded }
67    }
68}
69
70impl fmt::Debug for WireDriverChannel {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        self.as_raw_handle().fmt(f)
73    }
74}
75
76// SAFETY: `decode` only returns `Ok` if it wrote to the `decoded` field of the
77// handle, initializing it.
78unsafe impl<D: HandleDecoder + ?Sized> Decode<D> for WireDriverChannel {
79    fn decode(
80        mut slot: Slot<'_, Self>,
81        decoder: &mut D,
82        _: <Self as Constrained>::Constraint,
83    ) -> Result<(), DecodeError> {
84        munge!(let Self { encoded } = slot.as_mut());
85
86        match **encoded {
87            u32::MAX => {
88                let handle = decoder.take_raw_driver_handle()?;
89                munge!(let Self { mut decoded } = slot);
90                decoded.write(handle);
91            }
92            e => return Err(DecodeError::InvalidHandlePresence(e)),
93        }
94        Ok(())
95    }
96}
97
98impl Unconstrained for WireDriverChannel {}
99
100/// The FIDL wire type for optional [`DriverChannel`]s.
101///
102/// This type follows the FIDL wire format for handles, and is separate from the
103/// Zircon handle optional wire type. This ensures that we never confuse the two
104/// types when using FIDL.
105#[repr(C, align(4))]
106pub union WireOptionalDriverChannel {
107    encoded: WireU32,
108    decoded: fdf_handle_t,
109}
110
111impl Drop for WireOptionalDriverChannel {
112    fn drop(&mut self) {
113        if let Some(handle) = self.as_raw_handle() {
114            // SAFETY: If the return value from `as_raw_handle` is `Some`, then
115            // it is always non-zero.
116            let handle = unsafe { NonZero::new_unchecked(handle) };
117            // SAFETY: `WireDriverHandle` is always a valid `DriverHandle`.
118            let handle = unsafe { DriverHandle::new_unchecked(handle) };
119            drop(handle);
120        }
121    }
122}
123
124// SAFETY:
125// - `WireOptionalDriverHandle` doesn't reference any other decoded data.
126// - `WireOptionalDriverHandle` does not have any padding bytes.
127unsafe impl Wire for WireOptionalDriverChannel {
128    type Decoded<'de> = Self;
129
130    #[inline]
131    fn zero_padding(_: &mut MaybeUninit<Self>) {
132        // Wire optional driver handles have no padding
133    }
134}
135
136impl WireOptionalDriverChannel {
137    /// Encodes a driver handle as present in a slot.
138    pub fn set_encoded_present(out: &mut MaybeUninit<Self>) {
139        munge!(let Self { encoded } = out);
140        encoded.write(WireU32(u32::MAX));
141    }
142
143    /// Encodes a driver handle as absent in an output.
144    pub fn set_encoded_absent(out: &mut MaybeUninit<Self>) {
145        munge!(let Self { encoded } = out);
146        encoded.write(WireU32(0));
147    }
148
149    /// Returns whether a handle is present.
150    pub fn is_some(&self) -> bool {
151        self.as_raw_handle().is_some()
152    }
153
154    /// Returns whether a handle is absent.
155    pub fn is_none(&self) -> bool {
156        self.as_raw_handle().is_none()
157    }
158
159    /// Returns the underlying [`fdf_handle_t`], if any.
160    #[inline]
161    pub fn as_raw_handle(&self) -> Option<fdf_handle_t> {
162        // SAFETY: If we have a reference to `WireDriverHandle`, then it has
163        // been successfully decoded and the `decoded` field is safe to read.
164        let decoded = unsafe { self.decoded };
165        if decoded == 0 { None } else { Some(decoded) }
166    }
167}
168
169// SAFETY: `decode` only returns `Ok` if either:
170// - It wrote to the `decoded` field of the handle, initializing it.
171// - The handle's encoded (and decoded) value was zero, indicating `None`.
172unsafe impl<D: HandleDecoder + ?Sized> Decode<D> for WireOptionalDriverChannel {
173    fn decode(
174        mut slot: Slot<'_, Self>,
175        decoder: &mut D,
176        _: <Self as Constrained>::Constraint,
177    ) -> Result<(), DecodeError> {
178        munge!(let Self { encoded } = slot.as_mut());
179
180        match **encoded {
181            0 => (),
182            u32::MAX => {
183                let handle = decoder.take_raw_driver_handle()?;
184                munge!(let Self { mut decoded } = slot);
185                decoded.write(handle);
186            }
187            e => return Err(DecodeError::InvalidHandlePresence(e)),
188        }
189        Ok(())
190    }
191}
192
193impl Unconstrained for WireOptionalDriverChannel {}
194
195// SAFETY: `encode` calls `set_encoded_present`, which initializes all of the
196// bytes of `out`.
197unsafe impl<E: HandleEncoder + ?Sized> Encode<WireDriverChannel, E> for DriverChannel {
198    fn encode(
199        self,
200        encoder: &mut E,
201        out: &mut MaybeUninit<WireDriverChannel>,
202        _: (),
203    ) -> Result<(), EncodeError> {
204        let handle = self.channel.into_driver_handle();
205        // SAFETY: `self.into_raw()` returns a valid driver handle.
206        unsafe {
207            encoder.push_raw_driver_handle(handle.into_raw().get())?;
208        }
209        WireDriverChannel::set_encoded_present(out);
210        Ok(())
211    }
212}
213
214impl FromWire<WireDriverChannel> for DriverChannel {
215    fn from_wire(wire: WireDriverChannel) -> Self {
216        // SAFETY: `WireDriverHandle` is always non-zero.
217        let raw_handle = unsafe { NonZero::new_unchecked(wire.as_raw_handle()) };
218        // SAFETY: `WireDriverHandle` is always a valid `Handle`.
219        let handle = unsafe { DriverHandle::new_unchecked(raw_handle) };
220        // SAFETY: `WireDriverHandle` is always a valid `Channel`.
221        let channel = unsafe { Channel::from_driver_handle(handle) };
222        forget(wire);
223        DriverChannel::new(channel)
224    }
225}
226
227impl IntoNatural for WireDriverChannel {
228    type Natural = DriverChannel;
229}
230
231// SAFETY: `encode_option` calls either `set_encoded_present` or
232// `set_encoded_absent`, both of which initializes all of the bytes of `out`.
233unsafe impl<E: HandleEncoder + ?Sized> EncodeOption<WireOptionalDriverChannel, E>
234    for DriverChannel
235{
236    fn encode_option(
237        this: Option<Self>,
238        encoder: &mut E,
239        out: &mut MaybeUninit<WireOptionalDriverChannel>,
240        _: (),
241    ) -> Result<(), EncodeError> {
242        if let Some(driver_channel) = this {
243            let handle = driver_channel.channel.into_driver_handle();
244            // SAFETY: `self.into_raw()` returns a valid driver handle.
245            unsafe {
246                encoder.push_raw_driver_handle(handle.into_raw().get())?;
247            }
248            WireOptionalDriverChannel::set_encoded_present(out);
249        } else {
250            WireOptionalDriverChannel::set_encoded_absent(out);
251        }
252        Ok(())
253    }
254}
255
256impl FromWireOption<WireOptionalDriverChannel> for DriverChannel {
257    fn from_wire_option(wire: WireOptionalDriverChannel) -> Option<Self> {
258        let raw_handle = wire.as_raw_handle();
259        forget(wire);
260        raw_handle.map(|raw| {
261            // SAFETY: `WireDriverHandle::as_raw_handle()` only returns `Some`
262            // with a non-zero raw handle.
263            let raw_handle = unsafe { NonZero::new_unchecked(raw) };
264            // SAFETY: `wire` previously owned the valid driver handle. It has
265            // been forgotten, passing ownership to the returned `DriverHandle`.
266            let handle = unsafe { DriverHandle::new_unchecked(raw_handle) };
267            // SAFETY: `WireOptionalDriverChannel` is always a valid `Channel`.
268            let channel = unsafe { Channel::from_driver_handle(handle) };
269            DriverChannel::new(channel)
270        })
271    }
272}
273
274impl IntoNatural for WireOptionalDriverChannel {
275    type Natural = Option<DriverChannel>;
276}
277
278#[cfg(test)]
279mod tests {
280    use fdf_channel::arena::Arena;
281    use fdf_channel::message::Message;
282    use fdf_core::handle::MixedHandleType;
283    use fidl_next::{Chunk, DecoderExt as _, EncoderExt as _, chunks};
284
285    use crate::{RecvBuffer, SendBuffer};
286
287    use super::*;
288
289    #[test]
290    fn roundtrip() {
291        let (channel, _) = Channel::<[Chunk]>::create();
292        // SAFETY: this handle won't be used as a driver handle.
293        let handle_raw = unsafe { channel.driver_handle().get_raw() };
294        let driver_channel = DriverChannel::new(channel);
295
296        let mut encoder = SendBuffer::new();
297        encoder.encode_next(driver_channel, ()).unwrap();
298
299        assert_eq!(encoder.handles.len(), 1);
300        let driver_ref = encoder.handles[0].as_ref().unwrap().resolve_ref();
301        let MixedHandleType::Driver(handle) = &driver_ref else {
302            panic!("expected a driver handle");
303        };
304        assert_eq!(unsafe { handle.get_raw() }, handle_raw);
305        assert_eq!(encoder.data, chunks![0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00],);
306        drop(driver_ref);
307
308        let arena = Arena::new();
309        let data = arena.insert_boxed_slice(encoder.data.into_boxed_slice());
310        let handles = arena.insert_boxed_slice(encoder.handles.into_boxed_slice());
311        let buffer = Some(Message::new(&arena, Some(data), Some(handles)));
312        let decoder = RecvBuffer { buffer, data_offset: 0, handle_offset: 0 };
313
314        let decoded = decoder.decode::<WireDriverChannel>().unwrap();
315        assert_eq!(decoded.as_raw_handle(), handle_raw.get());
316
317        let handle = decoded.take();
318        let roundtripped_raw = unsafe { handle.channel.driver_handle().get_raw() };
319        assert_eq!(roundtripped_raw, handle_raw);
320    }
321
322    #[test]
323    fn roundtrip_some() {
324        let (channel, _) = Channel::<[Chunk]>::create();
325        // SAFETY: this handle won't be used as a driver handle.
326        let handle_raw = unsafe { channel.driver_handle().get_raw() };
327        let driver_channel = DriverChannel::new(channel);
328
329        let mut encoder = SendBuffer::new();
330        encoder.encode_next(Some(driver_channel), ()).unwrap();
331
332        assert_eq!(encoder.handles.len(), 1);
333        let driver_ref = encoder.handles[0].as_ref().unwrap().resolve_ref();
334        let MixedHandleType::Driver(handle) = &driver_ref else {
335            panic!("expected a driver handle");
336        };
337        assert_eq!(unsafe { handle.get_raw() }, handle_raw);
338        assert_eq!(encoder.data, chunks![0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00],);
339        drop(driver_ref);
340
341        let arena = Arena::new();
342        let data = arena.insert_boxed_slice(encoder.data.into_boxed_slice());
343        let handles = arena.insert_boxed_slice(encoder.handles.into_boxed_slice());
344        let buffer = Some(Message::new(&arena, Some(data), Some(handles)));
345        let decoder = RecvBuffer { buffer, data_offset: 0, handle_offset: 0 };
346
347        let decoded = decoder.decode::<WireOptionalDriverChannel>().unwrap();
348        assert_eq!(decoded.as_raw_handle(), Some(handle_raw.get()));
349
350        let handle = decoded.take();
351        let roundtripped_raw = unsafe { handle.unwrap().channel.driver_handle().get_raw() };
352        assert_eq!(roundtripped_raw, handle_raw);
353    }
354
355    #[test]
356    fn roundtrip_none() {
357        let mut encoder = SendBuffer::new();
358        encoder.encode_next(Option::<DriverChannel>::None, ()).unwrap();
359
360        assert_eq!(encoder.handles.len(), 0);
361        assert_eq!(encoder.data, chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],);
362
363        let arena = Arena::new();
364        let data = arena.insert_boxed_slice(encoder.data.into_boxed_slice());
365        let handles = arena.insert_boxed_slice(encoder.handles.into_boxed_slice());
366        let buffer = Some(Message::new(&arena, Some(data), Some(handles)));
367        let decoder = RecvBuffer { buffer, data_offset: 0, handle_offset: 0 };
368
369        let decoded = decoder.decode::<WireOptionalDriverChannel>().unwrap();
370        assert_eq!(decoded.as_raw_handle(), None);
371
372        let handle = decoded.take();
373        assert!(handle.is_none());
374    }
375}