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 107 108
// 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 [`Encoder`] trait and a basic implementation of it.
mod basic;
pub use self::basic::*;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::slice::from_mut;
use crate::encode::EncodeError;
use crate::{Encode, Slot};
/// An encoder for FIDL messages.
pub trait Encoder {
/// Returns the number of bytes written to the encoder.
fn bytes_written(&self) -> usize;
/// Writes zeroed bytes to the end of the encoder.
///
/// Additional bytes are written to pad the written data to a multiple of [`CHUNK_SIZE`].
fn reserve(&mut self, len: usize);
/// Copies bytes to the end of the encoder.
///
/// Additional bytes are written to pad the written data to a multiple of [`CHUNK_SIZE`].
fn write(&mut self, bytes: &[u8]);
/// Rewrites bytes at a position in the encoder.
fn rewrite(&mut self, pos: usize, bytes: &[u8]);
/// Returns the number of handles written to the encoder.
///
/// 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_handle_count(&self) -> usize;
}
/// Extension methods for [`Encoder`].
pub trait EncoderExt {
/// Pre-allocates space for a slice of elements.
fn preallocate<T>(&mut self, len: usize) -> Preallocated<'_, Self, T>;
// TODO: rename to encode_next_slice and encode_next
/// Encodes a slice of elements.
///
/// Returns `Err` if encoding failed.
fn encode_slice<T: Encode<Self>>(&mut self, values: &mut [T]) -> Result<(), EncodeError>;
/// Encodes a value.
///
/// Returns `Err` if encoding failed.
fn encode<T: Encode<Self>>(&mut self, value: &mut T) -> Result<(), EncodeError>;
}
impl<E: Encoder + ?Sized> EncoderExt for E {
fn preallocate<T>(&mut self, len: usize) -> Preallocated<'_, Self, T> {
let pos = self.bytes_written();
let len_bytes = len * size_of::<T>();
// Zero out the next `count` bytes
self.reserve(len_bytes);
Preallocated { encoder: self, pos, end: pos + len_bytes, _phantom: PhantomData }
}
fn encode_slice<T: Encode<Self>>(&mut self, values: &mut [T]) -> Result<(), EncodeError> {
let mut slots = self.preallocate::<T::Encoded<'_>>(values.len());
let mut backing = MaybeUninit::<T::Encoded<'_>>::uninit();
for value in values {
let mut slot = Slot::new(&mut backing);
value.encode(slots.encoder, slot.as_mut())?;
slots.write_next(slot);
}
Ok(())
}
fn encode<T: Encode<Self>>(&mut self, value: &mut T) -> Result<(), EncodeError> {
self.encode_slice(from_mut(value))
}
}
/// A pre-allocated slice of elements
pub struct Preallocated<'a, E: ?Sized, T> {
/// The encoder.
pub encoder: &'a mut E,
pos: usize,
end: usize,
_phantom: PhantomData<T>,
}
impl<E: Encoder + ?Sized, T> Preallocated<'_, E, T> {
/// Writes into the next pre-allocated slot in the encoder.
pub fn write_next(&mut self, slot: Slot<'_, T>) {
assert_ne!(self.pos, self.end, "attemped to write more slots than preallocated",);
self.encoder.rewrite(self.pos, slot.as_bytes());
self.pos += size_of::<T>();
}
}