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, Encodable, EncodableOption, Encode, EncodeError,
16    EncodeOption, FromWire, FromWireOption, 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
195impl Encodable for DriverChannel {
196    type Encoded = WireDriverChannel;
197}
198
199// SAFETY: `encode` calls `set_encoded_present`, which initializes all of the
200// bytes of `out`.
201unsafe impl<E: HandleEncoder + ?Sized> Encode<E> for DriverChannel {
202    fn encode(
203        self,
204        encoder: &mut E,
205        out: &mut MaybeUninit<Self::Encoded>,
206        _: <WireDriverChannel as Constrained>::Constraint,
207    ) -> Result<(), EncodeError> {
208        let handle = self.channel.into_driver_handle();
209        // SAFETY: `self.into_raw()` returns a valid driver handle.
210        unsafe {
211            encoder.push_raw_driver_handle(handle.into_raw().get())?;
212        }
213        WireDriverChannel::set_encoded_present(out);
214        Ok(())
215    }
216}
217
218impl FromWire<WireDriverChannel> for DriverChannel {
219    fn from_wire(wire: WireDriverChannel) -> Self {
220        // SAFETY: `WireDriverHandle` is always non-zero.
221        let raw_handle = unsafe { NonZero::new_unchecked(wire.as_raw_handle()) };
222        // SAFETY: `WireDriverHandle` is always a valid `Handle`.
223        let handle = unsafe { DriverHandle::new_unchecked(raw_handle) };
224        // SAFETY: `WireDriverHandle` is always a valid `Channel`.
225        let channel = unsafe { Channel::from_driver_handle(handle) };
226        forget(wire);
227        DriverChannel::new(channel)
228    }
229}
230
231impl IntoNatural for WireDriverChannel {
232    type Natural = DriverChannel;
233}
234
235impl EncodableOption for DriverChannel {
236    type EncodedOption = WireOptionalDriverChannel;
237}
238
239// SAFETY: `encode_option` calls either `set_encoded_present` or
240// `set_encoded_absent`, both of which initializes all of the bytes of `out`.
241unsafe impl<E: HandleEncoder + ?Sized> EncodeOption<E> for DriverChannel {
242    fn encode_option(
243        this: Option<Self>,
244        encoder: &mut E,
245        out: &mut MaybeUninit<Self::EncodedOption>,
246        _: <Self::EncodedOption as Constrained>::Constraint,
247    ) -> Result<(), EncodeError> {
248        if let Some(driver_channel) = this {
249            let handle = driver_channel.channel.into_driver_handle();
250            // SAFETY: `self.into_raw()` returns a valid driver handle.
251            unsafe {
252                encoder.push_raw_driver_handle(handle.into_raw().get())?;
253            }
254            WireOptionalDriverChannel::set_encoded_present(out);
255        } else {
256            WireOptionalDriverChannel::set_encoded_absent(out);
257        }
258        Ok(())
259    }
260}
261
262impl FromWireOption<WireOptionalDriverChannel> for DriverChannel {
263    fn from_wire_option(wire: WireOptionalDriverChannel) -> Option<Self> {
264        let raw_handle = wire.as_raw_handle();
265        forget(wire);
266        raw_handle.map(|raw| {
267            // SAFETY: `WireDriverHandle::as_raw_handle()` only returns `Some`
268            // with a non-zero raw handle.
269            let raw_handle = unsafe { NonZero::new_unchecked(raw) };
270            // SAFETY: `wire` previously owned the valid driver handle. It has
271            // been forgotten, passing ownership to the returned `DriverHandle`.
272            let handle = unsafe { DriverHandle::new_unchecked(raw_handle) };
273            // SAFETY: `WireOptionalDriverChannel` is always a valid `Channel`.
274            let channel = unsafe { Channel::from_driver_handle(handle) };
275            DriverChannel::new(channel)
276        })
277    }
278}
279
280impl IntoNatural for WireOptionalDriverChannel {
281    type Natural = Option<DriverChannel>;
282}
283
284#[cfg(test)]
285mod tests {
286    use fdf_channel::arena::Arena;
287    use fdf_channel::message::Message;
288    use fdf_core::handle::MixedHandleType;
289    use fidl_next::{Chunk, DecoderExt as _, EncoderExt as _, chunks};
290
291    use crate::{RecvBuffer, SendBuffer};
292
293    use super::*;
294
295    #[test]
296    fn roundtrip() {
297        let (channel, _) = Channel::<[Chunk]>::create();
298        // SAFETY: this handle won't be used as a driver handle.
299        let handle_raw = unsafe { channel.driver_handle().get_raw() };
300        let driver_channel = DriverChannel::new(channel);
301
302        let mut encoder = SendBuffer::new();
303        encoder.encode_next(driver_channel, ()).unwrap();
304
305        assert_eq!(encoder.handles.len(), 1);
306        let driver_ref = encoder.handles[0].as_ref().unwrap().resolve_ref();
307        let MixedHandleType::Driver(handle) = &driver_ref else {
308            panic!("expected a driver handle");
309        };
310        assert_eq!(unsafe { handle.get_raw() }, handle_raw);
311        assert_eq!(encoder.data, chunks![0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00],);
312        drop(driver_ref);
313
314        let arena = Arena::new();
315        let data = arena.insert_boxed_slice(encoder.data.into_boxed_slice());
316        let handles = arena.insert_boxed_slice(encoder.handles.into_boxed_slice());
317        let buffer = Some(Message::new(&arena, Some(data), Some(handles)));
318        let decoder = RecvBuffer { buffer, data_offset: 0, handle_offset: 0 };
319
320        let decoded = decoder.decode::<WireDriverChannel>().unwrap();
321        assert_eq!(decoded.as_raw_handle(), handle_raw.get());
322
323        let handle = decoded.take();
324        let roundtripped_raw = unsafe { handle.channel.driver_handle().get_raw() };
325        assert_eq!(roundtripped_raw, handle_raw);
326    }
327
328    #[test]
329    fn roundtrip_some() {
330        let (channel, _) = Channel::<[Chunk]>::create();
331        // SAFETY: this handle won't be used as a driver handle.
332        let handle_raw = unsafe { channel.driver_handle().get_raw() };
333        let driver_channel = DriverChannel::new(channel);
334
335        let mut encoder = SendBuffer::new();
336        encoder.encode_next(Some(driver_channel), ()).unwrap();
337
338        assert_eq!(encoder.handles.len(), 1);
339        let driver_ref = encoder.handles[0].as_ref().unwrap().resolve_ref();
340        let MixedHandleType::Driver(handle) = &driver_ref else {
341            panic!("expected a driver handle");
342        };
343        assert_eq!(unsafe { handle.get_raw() }, handle_raw);
344        assert_eq!(encoder.data, chunks![0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00],);
345        drop(driver_ref);
346
347        let arena = Arena::new();
348        let data = arena.insert_boxed_slice(encoder.data.into_boxed_slice());
349        let handles = arena.insert_boxed_slice(encoder.handles.into_boxed_slice());
350        let buffer = Some(Message::new(&arena, Some(data), Some(handles)));
351        let decoder = RecvBuffer { buffer, data_offset: 0, handle_offset: 0 };
352
353        let decoded = decoder.decode::<WireOptionalDriverChannel>().unwrap();
354        assert_eq!(decoded.as_raw_handle(), Some(handle_raw.get()));
355
356        let handle = decoded.take();
357        let roundtripped_raw = unsafe { handle.unwrap().channel.driver_handle().get_raw() };
358        assert_eq!(roundtripped_raw, handle_raw);
359    }
360
361    #[test]
362    fn roundtrip_none() {
363        let mut encoder = SendBuffer::new();
364        encoder.encode_next(Option::<DriverChannel>::None, ()).unwrap();
365
366        assert_eq!(encoder.handles.len(), 0);
367        assert_eq!(encoder.data, chunks![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],);
368
369        let arena = Arena::new();
370        let data = arena.insert_boxed_slice(encoder.data.into_boxed_slice());
371        let handles = arena.insert_boxed_slice(encoder.handles.into_boxed_slice());
372        let buffer = Some(Message::new(&arena, Some(data), Some(handles)));
373        let decoder = RecvBuffer { buffer, data_offset: 0, handle_offset: 0 };
374
375        let decoded = decoder.decode::<WireOptionalDriverChannel>().unwrap();
376        assert_eq!(decoded.as_raw_handle(), None);
377
378        let handle = decoded.take();
379        assert!(handle.is_none());
380    }
381}