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