1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
// Copyright 2024 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! The core [`Decoder`] trait and a basic implementation of it.
mod basic;
pub use self::basic::*;
use crate::{Chunk, Decode, DecodeError, Owned, Slot, CHUNK_SIZE};
/// A decoder for FIDL messages.
pub trait Decoder<'buf> {
/// Takes a slice of `Chunk`s from the decoder.
///
/// Returns `Err` if the decoder doesn't have enough chunks left.
fn take_chunks(&mut self, count: usize) -> Result<&'buf mut [Chunk], DecodeError>;
/// Takes the next `count` handles from the decoder.
///
/// This method exposes details about Fuchsia resources that plain old FIDL shouldn't need to
/// know about. Do not use this method outside of this crate.
#[doc(hidden)]
fn __internal_take_handles(&mut self, _: usize) -> Result<(), DecodeError>;
/// Returns the number of handles remaining in the decoder.
///
/// This method exposes details about Fuchsia resources that plain old FIDL shouldn't need to
/// know about. Do not use this method outside of this crate.
#[doc(hidden)]
fn __internal_handles_remaining(&mut self) -> usize;
}
/// Extension methods for [`Decoder`].
pub trait DecoderExt<'buf> {
/// Takes enough chunks for a `T`, returning a `Slot` of the taken value.
fn take_slot<T>(&mut self) -> Result<Slot<'buf, T>, DecodeError>;
/// Takes enough chunks for a slice of `T`, returning a `Slot` of the taken slice.
fn take_slice_slot<T>(&mut self, len: usize) -> Result<Slot<'buf, [T]>, DecodeError>;
/// Decodes a `T` and returns an `Owned` pointer to it.
///
/// Returns `Err` if decoding failed.
fn decode_next<T: Decode<Self>>(&mut self) -> Result<Owned<'buf, T>, DecodeError>;
/// Decodes a slice of `T` and returns an `Owned` pointer to it.
///
/// Returns `Err` if decoding failed.
fn decode_next_slice<T: Decode<Self>>(
&mut self,
len: usize,
) -> Result<Owned<'buf, [T]>, DecodeError>;
}
impl<'buf, D: Decoder<'buf> + ?Sized> DecoderExt<'buf> for D {
fn take_slot<T>(&mut self) -> Result<Slot<'buf, T>, DecodeError> {
// TODO: might be able to move this into a const for guaranteed const
// eval
assert!(
align_of::<T>() <= CHUNK_SIZE,
"attempted to take a slot for a type with an alignment higher \
than {}",
CHUNK_SIZE,
);
let count = size_of::<T>().div_ceil(CHUNK_SIZE);
let chunks = self.take_chunks(count)?;
// SAFETY: `result` is at least 8-aligned and points to at least enough
// bytes for a `T`.
unsafe { Ok(Slot::new_unchecked(chunks.as_mut_ptr().cast())) }
}
fn take_slice_slot<T>(&mut self, len: usize) -> Result<Slot<'buf, [T]>, DecodeError> {
assert!(
align_of::<T>() <= CHUNK_SIZE,
"attempted to take a slice slot for a type with an alignment \
higher than {}",
CHUNK_SIZE,
);
let count = (size_of::<T>() * len).div_ceil(CHUNK_SIZE);
let chunks = self.take_chunks(count)?;
// SAFETY: `result` is at least 8-aligned and points to at least enough
// bytes for a slice of `T` of length `len`.
unsafe { Ok(Slot::new_slice_unchecked(chunks.as_mut_ptr().cast(), len)) }
}
fn decode_next<T: Decode<Self>>(&mut self) -> Result<Owned<'buf, T>, DecodeError> {
let mut slot = self.take_slot::<T>()?;
T::decode(slot.as_mut(), self)?;
unsafe { Ok(Owned::new_unchecked(slot.as_mut_ptr())) }
}
fn decode_next_slice<T: Decode<Self>>(
&mut self,
len: usize,
) -> Result<Owned<'buf, [T]>, DecodeError> {
let mut slot = self.take_slice_slot::<T>(len)?;
for i in 0..len {
T::decode(slot.index(i), self)?;
}
unsafe { Ok(Owned::new_unchecked(slot.as_mut_ptr())) }
}
}