fidl_next_codec/
decoder.rs

1// Copyright 2024 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//! The core [`Decoder`] trait.
6
7use core::mem::take;
8use core::ptr::NonNull;
9use core::slice;
10
11use crate::{Chunk, Decode, DecodeError, Owned, Slot, CHUNK_SIZE};
12
13/// A decoder for FIDL handles (internal).
14pub trait InternalHandleDecoder {
15    /// Takes the next `count` handles from the decoder.
16    ///
17    /// This method exposes details about Fuchsia resources that plain old FIDL shouldn't need to
18    /// know about. Do not use this method outside of this crate.
19    #[doc(hidden)]
20    fn __internal_take_handles(&mut self, count: usize) -> Result<(), DecodeError>;
21
22    /// Returns the number of handles remaining in the decoder.
23    ///
24    /// This method exposes details about Fuchsia resources that plain old FIDL shouldn't need to
25    /// know about. Do not use this method outside of this crate.
26    #[doc(hidden)]
27    fn __internal_handles_remaining(&self) -> usize;
28}
29
30/// A decoder for FIDL messages.
31///
32/// # Safety
33///
34/// Pointers returned from `take_chunks` must:
35///
36/// - Point to `count` initialized `Chunk`s
37/// - Be valid for reads and writes
38/// - Remain valid until the decoder is dropped
39///
40/// The decoder **may be moved** without invalidating the returned pointers.
41pub unsafe trait Decoder: InternalHandleDecoder {
42    /// Takes a slice of `Chunk`s from the decoder, returning a pointer to them.
43    ///
44    /// Returns `Err` if the decoder doesn't have enough chunks left.
45    fn take_chunks_raw(&mut self, count: usize) -> Result<NonNull<Chunk>, DecodeError>;
46
47    /// Finishes decoding.
48    ///
49    /// Returns `Err` if the decoder did not finish successfully.
50    fn finish(&mut self) -> Result<(), DecodeError>;
51}
52
53impl InternalHandleDecoder for &mut [Chunk] {
54    #[inline]
55    fn __internal_take_handles(&mut self, _: usize) -> Result<(), DecodeError> {
56        Err(DecodeError::InsufficientHandles)
57    }
58
59    #[inline]
60    fn __internal_handles_remaining(&self) -> usize {
61        0
62    }
63}
64
65unsafe impl Decoder for &mut [Chunk] {
66    #[inline]
67    fn take_chunks_raw(&mut self, count: usize) -> Result<NonNull<Chunk>, DecodeError> {
68        if count > self.len() {
69            return Err(DecodeError::InsufficientData);
70        }
71
72        let chunks = take(self);
73        let (prefix, suffix) = unsafe { chunks.split_at_mut_unchecked(count) };
74        *self = suffix;
75        unsafe { Ok(NonNull::new_unchecked(prefix.as_mut_ptr())) }
76    }
77
78    #[inline]
79    fn finish(&mut self) -> Result<(), DecodeError> {
80        if !self.is_empty() {
81            return Err(DecodeError::ExtraBytes { num_extra: self.len() * CHUNK_SIZE });
82        }
83
84        Ok(())
85    }
86}
87
88/// Extension methods for [`Decoder`].
89pub trait DecoderExt {
90    /// Takes a slice of `Chunk`s from the decoder.
91    fn take_chunks<'buf>(
92        self: &mut &'buf mut Self,
93        count: usize,
94    ) -> Result<&'buf mut [Chunk], DecodeError>;
95
96    /// Takes enough chunks for a `T`, returning a `Slot` of the taken value.
97    fn take_slot<'buf, T>(self: &mut &'buf mut Self) -> Result<Slot<'buf, T>, DecodeError>;
98
99    /// Takes enough chunks for a slice of `T`, returning a `Slot` of the taken slice.
100    fn take_slice_slot<'buf, T>(
101        self: &mut &'buf mut Self,
102        len: usize,
103    ) -> Result<Slot<'buf, [T]>, DecodeError>;
104
105    /// Decodes a `T` and returns an `Owned` pointer to it.
106    ///
107    /// Returns `Err` if decoding failed.
108    fn decode_next<'buf, T: Decode<Self>>(
109        self: &mut &'buf mut Self,
110    ) -> Result<Owned<'buf, T>, DecodeError>;
111
112    /// Decodes a slice of `T` and returns an `Owned` pointer to it.
113    ///
114    /// Returns `Err` if decoding failed.
115    fn decode_next_slice<'buf, T: Decode<Self>>(
116        self: &mut &'buf mut Self,
117        len: usize,
118    ) -> Result<Owned<'buf, [T]>, DecodeError>;
119
120    /// Finishes the decoder by decoding a `T`.
121    ///
122    /// On success, returns `Ok` of an `Owned` pointer to the decoded value. Returns `Err` if the
123    /// decoder did not finish successfully.
124    fn decode_last<'buf, T: Decode<Self>>(
125        self: &mut &'buf mut Self,
126    ) -> Result<Owned<'buf, T>, DecodeError>;
127
128    /// Finishes the decoder by decoding a slice of `T`.
129    ///
130    /// On success, returns `Ok` of an `Owned` pointer to the decoded slice. Returns `Err` if the
131    /// decoder did not finish successfully.
132    fn decode_last_slice<'buf, T: Decode<Self>>(
133        self: &mut &'buf mut Self,
134        len: usize,
135    ) -> Result<Owned<'buf, [T]>, DecodeError>;
136}
137
138impl<D: Decoder + ?Sized> DecoderExt for D {
139    fn take_chunks<'buf>(
140        self: &mut &'buf mut Self,
141        count: usize,
142    ) -> Result<&'buf mut [Chunk], DecodeError> {
143        self.take_chunks_raw(count).map(|p| unsafe { slice::from_raw_parts_mut(p.as_ptr(), count) })
144    }
145
146    fn take_slot<'buf, T>(self: &mut &'buf mut Self) -> Result<Slot<'buf, T>, DecodeError> {
147        // TODO: might be able to move this into a const for guaranteed const
148        // eval
149        assert!(
150            align_of::<T>() <= CHUNK_SIZE,
151            "attempted to take a slot for a type with an alignment higher \
152             than {}",
153            CHUNK_SIZE,
154        );
155
156        let count = size_of::<T>().div_ceil(CHUNK_SIZE);
157        let chunks = self.take_chunks(count)?;
158        // SAFETY: `result` is at least 8-aligned and points to at least enough
159        // bytes for a `T`.
160        unsafe { Ok(Slot::new_unchecked(chunks.as_mut_ptr().cast())) }
161    }
162
163    fn take_slice_slot<'buf, T>(
164        self: &mut &'buf mut Self,
165        len: usize,
166    ) -> Result<Slot<'buf, [T]>, DecodeError> {
167        assert!(
168            align_of::<T>() <= CHUNK_SIZE,
169            "attempted to take a slice slot for a type with an alignment \
170             higher than {}",
171            CHUNK_SIZE,
172        );
173
174        let count = (size_of::<T>() * len).div_ceil(CHUNK_SIZE);
175        let chunks = self.take_chunks(count)?;
176        // SAFETY: `result` is at least 8-aligned and points to at least enough
177        // bytes for a slice of `T` of length `len`.
178        unsafe { Ok(Slot::new_slice_unchecked(chunks.as_mut_ptr().cast(), len)) }
179    }
180
181    fn decode_next<'buf, T: Decode<Self>>(
182        self: &mut &'buf mut Self,
183    ) -> Result<Owned<'buf, T>, DecodeError> {
184        let mut slot = self.take_slot::<T>()?;
185        T::decode(slot.as_mut(), self)?;
186        unsafe { Ok(Owned::new_unchecked(slot.as_mut_ptr())) }
187    }
188
189    fn decode_next_slice<'buf, T: Decode<Self>>(
190        self: &mut &'buf mut Self,
191        len: usize,
192    ) -> Result<Owned<'buf, [T]>, DecodeError> {
193        let mut slot = self.take_slice_slot::<T>(len)?;
194        for i in 0..len {
195            T::decode(slot.index(i), self)?;
196        }
197        unsafe { Ok(Owned::new_unchecked(slot.as_mut_ptr())) }
198    }
199
200    fn decode_last<'buf, T: Decode<Self>>(
201        self: &mut &'buf mut Self,
202    ) -> Result<Owned<'buf, T>, DecodeError> {
203        let result = self.decode_next()?;
204        self.finish()?;
205        Ok(result)
206    }
207
208    fn decode_last_slice<'buf, T: Decode<Self>>(
209        self: &mut &'buf mut Self,
210        len: usize,
211    ) -> Result<Owned<'buf, [T]>, DecodeError> {
212        let result = self.decode_next_slice(len)?;
213        self.finish()?;
214        Ok(result)
215    }
216}