Skip to main content

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