blob: a5dc8cf98fd31fcf628ce941bb3df8d67187f995 [file] [log] [blame]
// Copyright 2018 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.
//! Encoding contains functions and traits for FIDL2 encoding and decoding.
use crate::invoke_for_handle_types;
use {
crate::handle::{Handle, HandleBased, MessageBuf},
crate::{Error, Result},
bitflags::bitflags,
fuchsia_zircon_status as zx_status,
static_assertions::{assert_not_impl_any, assert_obj_safe},
std::{cell::RefCell, cmp, convert::TryFrom, mem, ptr, str, u32, u64},
};
thread_local!(static CODING_BUF: RefCell<MessageBuf> = RefCell::new(MessageBuf::new()));
const MIN_TLS_CODING_BUF_SIZE: usize = 512;
/// Acquire a mutable reference to the thread-local encoding buffers.
///
/// This function may not be called recursively.
pub fn with_tls_coding_bufs<R>(f: impl FnOnce(&mut Vec<u8>, &mut Vec<Handle>) -> R) -> R {
CODING_BUF.with(|buf| {
let mut buf = buf.borrow_mut();
let (bytes, handles) = buf.split_mut();
if bytes.capacity() == 0 {
bytes.reserve(MIN_TLS_CODING_BUF_SIZE);
}
let res = f(bytes, handles);
buf.clear();
res
})
}
/// Encodes the provided type into the thread-local encoding buffers.
///
/// This function may not be called recursively.
pub fn with_tls_encoded<T, E: From<Error>>(
val: &mut impl Encodable,
f: impl FnOnce(&mut Vec<u8>, &mut Vec<Handle>) -> std::result::Result<T, E>,
) -> std::result::Result<T, E> {
with_tls_coding_bufs(|bytes, handles| {
Encoder::encode(bytes, handles, val)?;
f(bytes, handles)
})
}
/// Resize a vector without zeroing added bytes.
///
/// The type `T` must be `Copy`. This is not enforced in the type signature
/// because it is used in generic contexts where verifying this requires looking
/// at control flow. See `decode_vector` for an example.
///
/// # Safety
///
/// This is unsafe when `new_len > old_len` because it leaves new elements at
/// indices `old_len..new_len` unintialized. The caller must overwrite all the
/// new elements before reading them. "Reading" includes any operation that
/// extends the vector, such as `push`, because this could reallocate the vector
/// and copy the uninitialized bytes.
///
/// FIDL conformance tests are used to validate that there are no uninitialized
/// bytes in the output across a range types and values.
unsafe fn resize_vec_no_zeroing<T>(buf: &mut Vec<T>, new_len: usize) {
if new_len > buf.capacity() {
buf.reserve(new_len - buf.len());
}
// Safety:
// - `new_len` must be less than or equal to `capacity()`:
// The if-statement above guarantees this.
// - The elements at `old_len..new_len` must be initialized:
// They are purposely left uninitialized, making this function unsafe.
buf.set_len(new_len);
}
/// Rounds `x` up if necessary so that it is a multiple of `align`.
///
/// Requires `align` to be a (nonzero) power of two.
pub fn round_up_to_align(x: usize, align: usize) -> usize {
debug_assert_ne!(align, 0);
debug_assert_eq!(align & (align - 1), 0);
// https://en.wikipedia.org/wiki/Data_structure_alignment#Computing_padding
(x + align - 1) & !(align - 1)
}
/// Split off the first element from a mutable slice.
fn split_off_first_mut<'a, T>(slice: &mut &'a mut [T]) -> Result<&'a mut T> {
split_off_front_mut(slice, 1).map(|res| &mut res[0])
}
/// Split of the first `n` mutable bytes from `slice`.
fn split_off_front_mut<'a, T>(slice: &mut &'a mut [T], n: usize) -> Result<&'a mut [T]> {
if n > slice.len() {
return Err(Error::OutOfRange);
}
let original = take_slice_mut(slice);
let (head, tail) = original.split_at_mut(n);
*slice = tail;
Ok(head)
}
/// Empty out a mutable slice.
fn take_slice_mut<'a, T>(x: &mut &'a mut [T]) -> &'a mut [T] {
mem::replace(x, &mut [])
}
#[doc(hidden)] // only exported for macro use
pub fn take_handle<T: HandleBased>(handle: &mut T) -> Handle {
let invalid = T::from_handle(Handle::invalid());
mem::replace(handle, invalid).into_handle()
}
/// The maximum recursion depth of encoding and decoding.
/// Each nested aggregate type (structs, unions, arrays, or vectors) counts as one step in the
/// recursion depth.
pub const MAX_RECURSION: usize = 32;
/// Indicates that an optional value is present.
pub const ALLOC_PRESENT_U64: u64 = u64::MAX;
/// Indicates that an optional value is present.
pub const ALLOC_PRESENT_U32: u32 = u32::MAX;
/// Indicates that an optional value is absent.
pub const ALLOC_ABSENT_U64: u64 = 0;
/// Indicates that an optional value is absent.
pub const ALLOC_ABSENT_U32: u32 = 0;
/// Special ordinal signifying an epitaph message.
pub const EPITAPH_ORDINAL: u64 = 0xffffffffffffffffu64;
/// The current wire format magic number
pub const MAGIC_NUMBER_INITIAL: u8 = 1;
/// Context for encoding and decoding.
///
/// This is currently empty. We keep it around to ease the implementation of
/// context-dependent behavior for future migrations.
///
/// WARNING: Do not construct this directly unless you know what you're doing.
/// FIDL uses `Context` to coordinate soft migrations, so improper uses of it
/// could result in ABI breakage.
#[derive(Clone, Copy, Debug)]
pub struct Context {}
impl Context {
/// Returns the header flags to set when encoding with this context.
fn header_flags(&self) -> HeaderFlags {
HeaderFlags::UNIONS_USE_XUNION_FORMAT
}
}
/// Encoding state
#[derive(Debug)]
pub struct Encoder<'a> {
/// Buffer to write output data into.
///
/// New chunks of out-of-line data should be appended to the end of the `Vec`.
/// `buf` should be resized to be large enough for any new data *prior* to encoding the inline
/// portion of that data.
buf: &'a mut Vec<u8>,
/// Buffer to write output handles into.
handles: &'a mut Vec<Handle>,
/// Encoding context.
context: &'a Context,
}
/// The default context for encoding.
/// During migrations, this controls the default write path.
fn default_encode_context() -> Context {
Context {}
}
impl<'a> Encoder<'a> {
/// FIDL2-encodes `x` into the provided data and handle buffers.
pub fn encode<T: Encodable + ?Sized>(
buf: &'a mut Vec<u8>,
handles: &'a mut Vec<Handle>,
x: &mut T,
) -> Result<()> {
let context = default_encode_context();
Self::encode_with_context(&context, buf, handles, x)
}
/// FIDL2-encodes `x` into the provided data and handle buffers, using the
/// specified encoding context.
///
/// WARNING: Do not call this directly unless you know what you're doing.
/// FIDL uses `Context` to coordinate soft migrations, so improper uses of
/// this function could result in ABI breakage.
pub fn encode_with_context<T: Encodable + ?Sized>(
context: &Context,
buf: &'a mut Vec<u8>,
handles: &'a mut Vec<Handle>,
x: &mut T,
) -> Result<()> {
fn prepare_for_encoding<'a>(
context: &'a Context,
buf: &'a mut Vec<u8>,
handles: &'a mut Vec<Handle>,
ty_inline_size: usize,
) -> Encoder<'a> {
let aligned_inline_size = round_up_to_align(ty_inline_size, 8);
// Safety: The uninitialized elements are assigned in prepare_for_encoding and
// x.encode.
unsafe {
resize_vec_no_zeroing(buf, aligned_inline_size);
}
handles.truncate(0);
let mut encoder = Encoder { buf, handles, context };
encoder.padding(ty_inline_size, aligned_inline_size - ty_inline_size);
encoder
}
let mut encoder = prepare_for_encoding(context, buf, handles, x.inline_size(context));
x.encode(&mut encoder, 0, 0)
}
/// Returns the inline alignment of an object of type `Target` for this encoder.
pub fn inline_align_of<Target: Encodable>(&self) -> usize {
<Target as Layout>::inline_align(&self.context)
}
/// Returns the inline size of the given object for this encoder.
pub fn inline_size_of<Target: Encodable>(&self) -> usize {
<Target as Layout>::inline_size(&self.context)
}
/// Extends buf by `len` bytes and calls the provided closure to write
/// out-of-line data, with `offset` set to the start of the new region.
pub fn write_out_of_line<F>(&mut self, len: usize, recursion_depth: usize, f: F) -> Result<()>
where
F: FnOnce(&mut Encoder<'_>, usize, usize) -> Result<()>,
{
let new_offset = self.buf.len();
let new_depth = recursion_depth + 1;
Self::check_recursion_depth(new_depth)?;
let padded_len = round_up_to_align(len, 8);
// Safety: The uninitialized elements are assigned in self.padding and f.
unsafe {
resize_vec_no_zeroing(self.buf, self.buf.len() + padded_len);
}
self.padding(new_offset + len, padded_len - len);
f(self, new_offset, new_depth)
}
/// Validate that the recursion depth is within the limit.
pub fn check_recursion_depth(recursion_depth: usize) -> Result<()> {
if recursion_depth > MAX_RECURSION {
return Err(Error::MaxRecursionDepth);
}
Ok(())
}
/// Append bytes to the very end (out-of-line) of the buffer.
pub fn append_bytes(&mut self, bytes: &[u8]) {
self.buf.extend_from_slice(bytes);
let new_len = round_up_to_align(self.buf.len(), 8);
self.buf.resize(new_len, 0);
}
/// Append handles to the buffer.
pub fn append_handles(&mut self, handles: &mut [Handle]) {
self.handles.reserve(handles.len());
for handle in handles {
self.handles.push(take_handle(handle));
}
}
/// Returns the encoder's context.
///
/// This is needed for accessing the context in macros during migrations.
pub fn context(&self) -> &Context {
self.context
}
/// Write padding at the specified offset.
#[inline(always)]
pub fn padding(&mut self, offset: usize, len: usize) {
if len == 0 {
return;
}
// In practice, this assertion should never fail because we ensure that
// padding is within an already allocated block outside of this
// function.
assert!(offset + len <= self.buf.len());
// Safety:
// - The pointer is valid for this range, as tested by the assertion above.
// - All u8 pointers are properly aligned.
unsafe {
std::ptr::write_bytes(self.buf.as_mut_ptr().offset(offset as isize), 0, len);
}
}
}
/// Decoding state
#[derive(Debug)]
pub struct Decoder<'a> {
/// The out of line depth.
depth: usize,
/// The the next offset to read from in buf.
offset: usize,
/// The end of the current inline block in buf.
end_block: usize,
/// Next out of line block in buf.
next_out_of_line: usize,
/// Buffer from which to read data.
buf: &'a [u8],
/// Buffer from which to read handles.
handles: &'a mut [Handle],
/// Decoding context.
context: &'a Context,
}
impl<'a> Decoder<'a> {
/// FIDL2-decodes a value of type `T` from the provided data and handle
/// buffers. Assumes the buffers came from inside a transaction message
/// wrapped by `header`.
pub fn decode_into<T: Decodable>(
header: &TransactionHeader,
buf: &'a [u8],
handles: &'a mut [Handle],
value: &mut T,
) -> Result<()> {
Self::decode_with_context(&header.decoding_context(), buf, handles, value)
}
/// FIDL2-decodes a value of type `T` from the provided data and handle
/// buffers, using the specified context.
///
/// WARNING: Do not call this directly unless you know what you're doing.
/// FIDL uses `Context` to coordinate soft migrations, so improper uses of
/// this function could result in ABI breakage.
pub fn decode_with_context<T: Decodable>(
context: &Context,
buf: &'a [u8],
handles: &'a mut [Handle],
value: &mut T,
) -> Result<()> {
let inline_size = T::inline_size(context);
let next_out_of_line = round_up_to_align(inline_size, 8);
if next_out_of_line > buf.len() {
return Err(Error::OutOfRange);
}
let mut decoder = Decoder {
depth: 0,
offset: 0,
end_block: next_out_of_line,
next_out_of_line: next_out_of_line,
buf,
handles,
context,
};
value.decode(&mut decoder)?;
debug_assert!(
decoder.offset == inline_size,
"Inline part of the buffer was not completely consumed. Most likely, this indicates a \
bug in the FIDL decoders.\n\
Offset: {}\n\
Block end offset: {}\n\
Buffer: {:X?}",
decoder.offset,
inline_size,
decoder.buf,
);
// Put this in a non-polymorphic helper function to reduce binary bloat.
fn post_decoding(decoder: &Decoder, next_out_of_line: usize) -> Result<()> {
if decoder.next_out_of_line < decoder.buf.len() {
return Err(Error::ExtraBytes);
}
if decoder.handles.len() != 0 {
return Err(Error::ExtraHandles);
}
for i in decoder.offset..next_out_of_line {
if decoder.buf[i] != 0 {
return Err(Error::NonZeroPadding {
padding_start: decoder.offset,
non_zero_pos: i,
});
}
}
Ok(())
}
post_decoding(&decoder, next_out_of_line)
}
/// Returns the next offset for reading and increases `offset` by `len`.
pub fn next_offset(&mut self, len: usize) -> usize {
let cur_offset = self.offset;
self.offset += len;
cur_offset
}
/// Take the next handle from the `handles` list and shift the list down by one element.
pub fn take_handle(&mut self) -> Result<Handle> {
split_off_first_mut(&mut self.handles).map(take_handle)
}
/// Runs the provided closure inside an decoder modified
/// to read out-of-line data.
pub fn read_out_of_line<F, R>(&mut self, len: usize, f: F) -> Result<R>
where
F: FnOnce(&mut Decoder<'_>) -> Result<R>,
{
// Save current state.
let old_offset = self.offset;
let old_end_block = self.end_block;
let old_next_out_of_line = self.next_out_of_line;
// Compute offsets for out of line block.
self.offset = self.next_out_of_line;
self.next_out_of_line = self.next_out_of_line + round_up_to_align(len, 8);
self.end_block = self.next_out_of_line;
if self.next_out_of_line > self.buf.len() {
return Err(Error::OutOfRange);
}
// Descend into block.
self.depth += 1;
if self.depth > MAX_RECURSION {
return Err(Error::MaxRecursionDepth);
}
let res = f(self)?;
self.depth -= 1;
// Ensure all bytes are consumed.
debug_assert!(
self.offset == old_next_out_of_line + len,
"Out of line block was not completely consumed. Most likely, this indicates a \
bug in the FIDL decoders.\n\
Offset: {}\n\
Block end offset: {}\n\
Buffer: {:X?}",
self.offset,
old_next_out_of_line + len,
self.buf,
);
// Validate padding bytes at the end of the block.
for i in self.offset..self.end_block {
if self.buf[i] != 0 {
return Err(Error::NonZeroPadding { padding_start: self.offset, non_zero_pos: i });
}
}
// Restore saved state.
self.offset = old_offset;
self.end_block = old_end_block;
// Return.
Ok(res)
}
/// Whether or not the current section of inline bytes has been fully read.
pub fn is_empty(&self) -> bool {
self.offset >= self.end_block
}
/// The number of handles that have not yet been consumed.
pub fn remaining_handles(&self) -> usize {
self.handles.len()
}
/// A convenience method to skip over the specified number of zero bytes used for padding, also
/// checking that all those bytes are in fact zeroes.
pub fn skip_padding(&mut self, len: usize) -> Result<()> {
if len == 0 {
// Skip body (so it can be optimized out).
return Ok(());
}
for i in self.offset..self.offset + len {
if self.buf[i] != 0 {
return Err(Error::NonZeroPadding { padding_start: self.offset, non_zero_pos: i });
}
}
self.offset += len;
Ok(())
}
/// Returns the inline alignment of an object of type `Target` for this decoder.
pub fn inline_align_of<Target: Decodable>(&self) -> usize {
Target::inline_align(&self.context)
}
/// Returns the inline size of an object of type `Target` for this decoder.
pub fn inline_size_of<Target: Decodable>(&self) -> usize {
Target::inline_size(&self.context)
}
/// Returns the decoder's context.
///
/// This is needed for accessing the context in macros during migrations.
pub fn context(&self) -> &Context {
self.context
}
/// The position of the next out of line block and the end of the current
/// blocks.
pub fn next_out_of_line(&self) -> usize {
self.next_out_of_line
}
/// The buffer holding the message to be decoded.
pub fn buffer(&self) -> &[u8] {
self.buf
}
}
/// A trait for specifying the inline layout of an encoded object.
pub trait Layout {
/// Returns the minimum required alignment of the inline portion of the
/// encoded object. It must be a (nonzero) power of two.
fn inline_align(context: &Context) -> usize
where
Self: Sized;
/// Returns the size of the inline portion of the encoded object, including
/// padding for the type's minimum alignment.
fn inline_size(context: &Context) -> usize
where
Self: Sized;
/// Returns `slice` viewed as bytes for types that support encoding and
/// decoding by simple copy. For all other types, returns `None`.
///
/// Simple copying only works for types when (1) the Rust data layout
/// matches the FIDL wire format, and (2) no validation is required. This is
/// the case for (arrays of) primitive integer types, because both FIDL and
/// Rust (we assume) use little-endian byte order, two's complement integer
/// representation, and arrays with no padding.
///
/// For more information:
/// https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout
/// https://doc.rust-lang.org/reference/types/numeric.html
fn slice_as_bytes(_slice: &mut [Self]) -> Option<&mut [u8]>
where
Self: Sized,
{
None
}
}
/// An object-safe extension of the `Layout` trait.
///
/// This trait should not be implemented directly. Instead, types should
/// implement `Layout` and rely on the automatic implementation of this one.
///
/// The purpose of this trait is to provide access to inline size and alignment
/// values through `dyn Encodable` trait objects, including generic contexts
/// where they are allowed such as `T: Encodable + ?Sized`.
pub trait LayoutObject: Layout {
/// See `Layout::inline_align`.
fn inline_align(&self, context: &Context) -> usize;
/// See `Layout::inline_size`.
fn inline_size(&self, context: &Context) -> usize;
}
assert_obj_safe!(LayoutObject);
impl<T: Layout> LayoutObject for T {
fn inline_align(&self, context: &Context) -> usize {
<T as Layout>::inline_align(context)
}
fn inline_size(&self, context: &Context) -> usize {
<T as Layout>::inline_size(context)
}
}
/// A type which can be FIDL2-encoded into a buffer.
///
/// Often an `Encodable` type should also be `Decodable`, but this is not always
/// the case. For example, both `String` and `&str` are encodable, but `&str` is
/// not decodable since it does not own any memory to store the string.
///
/// This trait is object-safe, meaning it is possible to create `dyn Encodable`
/// trait objects. Using them instead of generic `T: Encodable` types can help
/// reduce binary bloat. However, they can only be encoded directly: there are
/// no implementations of `Encodable` for enclosing types such as
/// `Vec<&dyn Encodable>`, and similarly for references, arrays, tuples, etc.
pub trait Encodable: LayoutObject {
/// Encode the object into the buffer. Any handles stored in the object are
/// swapped for `Handle::INVALID`. Callers should ensure that `offset` is a
/// multiple of `Layout::inline_align`, and that `encoder.buf` has room for
/// writing `Layout::inline_size` bytes at `offset`.
///
/// Implementations that encode out-of-line objects should pass
/// `recursion_depth` to `Encoder::write_out_of_line`, or manually call
/// `Encoder::check_recursion_depth(recursion_depth + 1)`.
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()>;
}
assert_obj_safe!(Encodable);
/// A type which can be FIDL2-decoded from a buffer.
///
/// This trait is not object-safe, since `new_empty` returns `Self`. This is not
/// really a problem: there are not many use cases for `dyn Decodable`.
pub trait Decodable: Layout {
/// Creates a new value of this type with an "empty" representation.
fn new_empty() -> Self;
/// Decodes an object of this type from the provided buffer and list of handles.
/// On success, returns `Self`, as well as the yet-unused tails of the data and handle buffers.
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()>;
}
macro_rules! impl_layout {
($ty:ty, align: $align:expr, size: $size:expr) => {
impl Layout for $ty {
fn inline_size(_context: &Context) -> usize {
$size
}
fn inline_align(_context: &Context) -> usize {
$align
}
}
};
}
macro_rules! impl_layout_forall_T {
($ty:ty, align: $align:expr, size: $size:expr) => {
impl<T: Layout> Layout for $ty {
fn inline_size(_context: &Context) -> usize {
$size
}
fn inline_align(_context: &Context) -> usize {
$align
}
}
};
}
// Implements `Layout` for a primitive integer type, overriding `slice_as_bytes`
// to enable encoding and decoding by simple copy.
macro_rules! impl_layout_int {
($int_ty:ty) => {
impl Layout for $int_ty {
fn inline_size(_context: &Context) -> usize {
mem::size_of::<$int_ty>()
}
fn inline_align(_context: &Context) -> usize {
mem::size_of::<$int_ty>()
}
fn slice_as_bytes(slice: &mut [Self]) -> Option<&mut [u8]> {
Some(zerocopy::AsBytes::as_bytes_mut(slice))
}
}
};
}
// This macro implements Encodable and Decodable for primitive integer types T.
// It ensures that T, [T; N], and Vec<T> are encoded/decoded by simple copy (via
// impl_layout_int), and that &[T] is encoded by simple copy (via
// impl_slice_encoding_by_copy).
//
// Some background on why we have the &[T] implementation: the FIDL type
// vector<T> becomes &mut dyn ExactSizeIterator<Item = T> (borrowed) or Vec<T>
// (owned) for most types. The former is a poor fit for vectors of primitives:
// we cannot optimize encoding from an iterator. For this reason, vectors of
// primitives are special-cased in fidlgen to use &[T] as the borrowed type.
//
// Caveat: bool uses &mut dyn ExactSizeIterator<Item = bool> because it cannot
// be optimized. Floats f32 and f64, though they cannot be optimized either, use
// &[f32] and &[f64].
// TODO(fxb/54368): Resolve this inconsistency.
macro_rules! impl_codable_int { ($($int_ty:ty,)*) => { $(
impl_layout_int!($int_ty);
impl Encodable for $int_ty {
fn encode(&mut self, encoder: &mut Encoder<'_>, offset: usize, _recursion_depth: usize) -> Result<()> {
encoder.buf[offset..offset+mem::size_of::<Self>()].copy_from_slice(&self.to_le_bytes());
Ok(())
}
}
impl Decodable for $int_ty {
fn new_empty() -> Self { 0 as $int_ty }
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
const SIZE: usize = mem::size_of::<$int_ty>();
let offset = decoder.next_offset(SIZE);
match <[u8; SIZE]>::try_from(&decoder.buf[offset .. offset+SIZE]) {
Ok(array) => {
*self = Self::from_le_bytes(array);
Ok(())
}
Err(_) => Err(Error::OutOfRange),
}
}
}
impl_slice_encoding_by_copy!($int_ty);
)* } }
// This is separate from impl_codable_int because floats will require validation
// in the future (FTP-055), so we can't encode/decode by simple copy.
macro_rules! impl_codable_float { ($($float_ty:ty,)*) => { $(
impl Layout for $float_ty {
fn inline_size(_context: &Context) -> usize { mem::size_of::<$float_ty>() }
fn inline_align(_context: &Context) -> usize { mem::size_of::<$float_ty>() }
}
impl Encodable for $float_ty {
fn encode(&mut self, encoder: &mut Encoder<'_>, offset: usize, _recursion_depth: usize) -> Result<()> {
encoder.buf[offset..offset+mem::size_of::<Self>()].copy_from_slice(&self.to_le_bytes());
Ok(())
}
}
impl Decodable for $float_ty {
fn new_empty() -> Self { 0 as $float_ty }
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
const SIZE: usize = mem::size_of::<$float_ty>();
let offset = decoder.next_offset(SIZE);
match <[u8; SIZE]>::try_from(&decoder.buf[offset .. offset+SIZE]) {
Ok(array) => {
*self = Self::from_le_bytes(array);
Ok(())
}
Err(_) => Err(Error::OutOfRange),
}
}
}
impl_slice_encoding_by_iter!($float_ty);
)* } }
// Common code used by impl_slice_encoding_by_{iter,copy}.
macro_rules! impl_slice_encoding_base {
($prim_ty:ty) => {
impl Layout for &[$prim_ty] {
fn inline_size(_context: &Context) -> usize {
16
}
fn inline_align(_context: &Context) -> usize {
8
}
}
impl Layout for Option<&[$prim_ty]> {
fn inline_size(_context: &Context) -> usize {
16
}
fn inline_align(_context: &Context) -> usize {
8
}
}
impl Encodable for Option<&[$prim_ty]> {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
match self {
None => encode_absent_vector(encoder, offset, recursion_depth),
Some(slice) => slice.encode(encoder, offset, recursion_depth),
}
}
}
};
}
// Encodes &[T] as a FIDL vector by encoding items one at a time.
macro_rules! impl_slice_encoding_by_iter {
($prim_ty:ty) => {
impl_slice_encoding_base!($prim_ty);
impl Encodable for &[$prim_ty] {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
encode_vector_from_iter(
encoder,
offset,
recursion_depth,
Some(self.iter().copied()),
)
}
}
};
}
// Encodes &[T] as a FIDL vector by simple copy.
macro_rules! impl_slice_encoding_by_copy {
($prim_ty:ty) => {
impl_slice_encoding_base!($prim_ty);
impl Encodable for &[$prim_ty] {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
(self.len() as u64).encode(encoder, offset, recursion_depth)?;
ALLOC_PRESENT_U64.encode(encoder, offset + 8, recursion_depth)?;
Encoder::check_recursion_depth(recursion_depth + 1)?;
if self.len() == 0 {
return Ok(());
}
// Encode by simple copy. See Layout::slice_as_bytes for more info.
let bytes = zerocopy::AsBytes::as_bytes(*self);
encoder.append_bytes(bytes);
Ok(())
}
}
};
}
impl_codable_int!(u16, u32, u64, i16, i32, i64,);
impl_codable_float!(f32, f64,);
impl_layout!(bool, align: 1, size: 1);
impl Encodable for bool {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
_recursion_depth: usize,
) -> Result<()> {
encoder.buf[offset] = if *self { 1 } else { 0 };
Ok(())
}
}
impl Decodable for bool {
fn new_empty() -> Self {
false
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
let offset = decoder.next_offset(1);
*self = match decoder.buf[offset] {
0 => false,
1 => true,
_ => return Err(Error::Invalid),
};
Ok(())
}
}
impl_layout_int!(u8);
impl_slice_encoding_by_copy!(u8);
impl Encodable for u8 {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
_recursion_depth: usize,
) -> Result<()> {
encoder.buf[offset] = *self;
Ok(())
}
}
impl Decodable for u8 {
fn new_empty() -> Self {
0
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
let offset = decoder.next_offset(1);
*self = decoder.buf[offset];
Ok(())
}
}
impl_layout_int!(i8);
impl_slice_encoding_by_copy!(i8);
impl Encodable for i8 {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
_recursion_depth: usize,
) -> Result<()> {
encoder.buf[offset] = *self as u8;
Ok(())
}
}
impl Decodable for i8 {
fn new_empty() -> Self {
0
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
let offset = decoder.next_offset(1);
*self = decoder.buf[offset] as i8;
Ok(())
}
}
/// Encodes `slice` as a FIDL array.
fn encode_array<T: Encodable>(
slice: &mut [T],
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
match T::slice_as_bytes(slice) {
Some(bytes) => {
// Encode by simple copy. See Layout::slice_as_bytes for more info.
encoder.buf[offset..offset + bytes.len()].copy_from_slice(bytes);
}
None => {
let stride = encoder.inline_size_of::<T>();
for (i, item) in slice.iter_mut().enumerate() {
item.encode(encoder, offset + i * stride, recursion_depth)?;
}
}
}
Ok(())
}
/// Decodes a FIDL array into `slice`.
fn decode_array<T: Decodable>(slice: &mut [T], decoder: &mut Decoder<'_>) -> Result<()> {
match T::slice_as_bytes(slice) {
Some(bytes) => {
// Decode by simple copy. See Layout::slice_as_bytes for more info.
let size = bytes.len();
let offset = decoder.next_offset(size);
bytes.copy_from_slice(&decoder.buf[offset..offset + size]);
}
None => {
for item in slice {
item.decode(decoder)?;
}
}
}
Ok(())
}
macro_rules! impl_codable_for_fixed_array { ($($len:expr,)*) => { $(
impl<T: Layout> Layout for [T; $len] {
fn inline_align(context: &Context) -> usize { T::inline_align(context) }
fn inline_size(context: &Context) -> usize { T::inline_size(context) * $len }
}
impl<T: Encodable> Encodable for [T; $len] {
fn encode(&mut self, encoder: &mut Encoder<'_>, offset: usize, recursion_depth: usize) -> Result<()> {
encode_array(self, encoder, offset, recursion_depth)
}
}
impl<T: Decodable> Decodable for [T; $len] {
fn new_empty() -> Self {
let mut arr = mem::MaybeUninit::<[T; $len]>::uninit();
unsafe {
let arr_ptr = arr.as_mut_ptr() as *mut T;
for i in 0..$len {
ptr::write(arr_ptr.offset(i as isize), T::new_empty());
}
arr.assume_init()
}
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
decode_array(self, decoder)
}
}
)* } }
// Unfortunately, we cannot be generic over the length of a fixed array
// even though its part of the type (this will hopefully be added in the
// future) so for now we implement encodable for only the first 33 fixed
// size array types.
#[rustfmt::skip]
impl_codable_for_fixed_array!( 0, 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,);
// Hack for FIDL library fuchsia.sysmem
impl_codable_for_fixed_array!(64,);
// Hack for FIDL library fuchsia.net
impl_codable_for_fixed_array!(256,);
/// Encode an optional vector-like component.
pub fn encode_vector<T: Encodable>(
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
slice_opt: Option<&mut [T]>,
) -> Result<()> {
match slice_opt {
None => encode_absent_vector(encoder, offset, recursion_depth),
Some(slice) => {
// Two u64: (len, present)
(slice.len() as u64).encode(encoder, offset, recursion_depth)?;
ALLOC_PRESENT_U64.encode(encoder, offset + 8, recursion_depth)?;
if slice.len() == 0 {
return Ok(());
}
let bytes_len = slice.len() * encoder.inline_size_of::<T>();
encoder.write_out_of_line(
bytes_len,
recursion_depth,
|encoder, offset, recursion_depth| {
encode_array(slice, encoder, offset, recursion_depth)
},
)
}
}
}
/// Encode an missing vector-like component.
pub fn encode_absent_vector(
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
0u64.encode(encoder, offset, recursion_depth)?;
ALLOC_ABSENT_U64.encode(encoder, offset + 8, recursion_depth)
}
/// Like `encode_vector`, but optimized for `&[u8]`.
fn encode_vector_from_bytes(
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
slice_opt: Option<&[u8]>,
) -> Result<()> {
match slice_opt {
None => encode_absent_vector(encoder, offset, recursion_depth),
Some(slice) => {
// Two u64: (len, present)
(slice.len() as u64).encode(encoder, offset, recursion_depth)?;
ALLOC_PRESENT_U64.encode(encoder, offset + 8, recursion_depth)?;
Encoder::check_recursion_depth(recursion_depth + 1)?;
encoder.append_bytes(slice);
Ok(())
}
}
}
/// Like `encode_vector`, but encodes from an iterator.
pub fn encode_vector_from_iter<Iter, T>(
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
iter_opt: Option<Iter>,
) -> Result<()>
where
Iter: ExactSizeIterator<Item = T>,
T: Encodable,
{
match iter_opt {
None => encode_absent_vector(encoder, offset, recursion_depth),
Some(iter) => {
// Two u64: (len, present)
(iter.len() as u64).encode(encoder, offset, recursion_depth)?;
ALLOC_PRESENT_U64.encode(encoder, offset + 8, recursion_depth)?;
if iter.len() == 0 {
return Ok(());
}
let bytes_len = iter.len() * encoder.inline_size_of::<T>();
encoder.write_out_of_line(
bytes_len,
recursion_depth,
|encoder, offset, recursion_depth| {
let stride = encoder.inline_size_of::<T>();
for (i, mut item) in iter.enumerate() {
item.encode(encoder, offset + stride * i, recursion_depth)?;
}
Ok(())
},
)
}
}
}
/// Attempts to decode a string into `string`, returning a `bool`
/// indicating whether or not a string was present.
fn decode_string(decoder: &mut Decoder<'_>, string: &mut String) -> Result<bool> {
let mut len: u64 = 0;
len.decode(decoder)?;
let mut present: u64 = 0;
present.decode(decoder)?;
match present {
ALLOC_ABSENT_U64 => {
return if len == 0 { Ok(false) } else { Err(Error::UnexpectedNullRef) }
}
ALLOC_PRESENT_U64 => {}
_ => return Err(Error::Invalid),
};
let len = len as usize;
decoder.read_out_of_line(len, |decoder| {
let offset = decoder.next_offset(len);
string.truncate(0);
let bytes = &decoder.buf[offset..offset + len];
string.push_str(str::from_utf8(bytes).map_err(|_| Error::Utf8Error)?);
Ok(true)
})
}
/// Attempts to decode a FIDL vector into `vec`, returning a `bool` indicating
/// whether the vector was present.
fn decode_vector<T: Decodable>(decoder: &mut Decoder<'_>, vec: &mut Vec<T>) -> Result<bool> {
let mut len: u64 = 0;
len.decode(decoder)?;
let mut present: u64 = 0;
present.decode(decoder)?;
match present {
ALLOC_ABSENT_U64 => {
return if len == 0 { Ok(false) } else { Err(Error::UnexpectedNullRef) }
}
ALLOC_PRESENT_U64 => {}
_ => return Err(Error::Invalid),
}
let len = len as usize;
let bytes_len = len * decoder.inline_size_of::<T>();
decoder.read_out_of_line(bytes_len, |decoder| {
if T::slice_as_bytes(vec).is_some() {
// Safety: The uninitalized elements are immediately written by
// `decode_array`, which always succeeds in the simple copy case.
unsafe {
resize_vec_no_zeroing(vec, len);
}
} else {
vec.resize_with(len, T::new_empty);
}
decode_array(vec, decoder)?;
Ok(true)
})
}
impl_layout!(&str, align: 8, size: 16);
impl Encodable for &str {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
encode_vector_from_bytes(encoder, offset, recursion_depth, Some(self.as_bytes()))
}
}
impl_layout!(String, align: 8, size: 16);
impl Encodable for String {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
encode_vector_from_bytes(encoder, offset, recursion_depth, Some(self.as_bytes()))
}
}
impl Decodable for String {
fn new_empty() -> Self {
String::new()
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
if decode_string(decoder, self)? {
Ok(())
} else {
Err(Error::NotNullable)
}
}
}
impl_layout!(Option<&str>, align: 8, size: 16);
impl Encodable for Option<&str> {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
encode_vector_from_bytes(
encoder,
offset,
recursion_depth,
self.as_ref().map(|x| x.as_bytes()),
)
}
}
impl_layout!(Option<String>, align: 8, size: 16);
impl Encodable for Option<String> {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
encode_vector_from_bytes(
encoder,
offset,
recursion_depth,
self.as_ref().map(|x| x.as_bytes()),
)
}
}
impl Decodable for Option<String> {
fn new_empty() -> Self {
None
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
let was_some;
{
let string = self.get_or_insert(String::new());
was_some = decode_string(decoder, string)?;
}
if !was_some {
*self = None
}
Ok(())
}
}
impl_layout_forall_T!(&mut dyn ExactSizeIterator<Item = T>, align: 8, size: 16);
impl<T: Encodable> Encodable for &mut dyn ExactSizeIterator<Item = T> {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
encode_vector_from_iter(encoder, offset, recursion_depth, Some(self))
}
}
impl_layout_forall_T!(Vec<T>, align: 8, size: 16);
impl<T: Encodable> Encodable for Vec<T> {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
encode_vector(encoder, offset, recursion_depth, Some(self))
}
}
impl<T: Decodable> Decodable for Vec<T> {
fn new_empty() -> Self {
Vec::new()
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
if decode_vector(decoder, self)? {
Ok(())
} else {
Err(Error::NotNullable)
}
}
}
impl_layout_forall_T!(Option<&mut dyn ExactSizeIterator<Item = T>>, align: 8, size: 16);
impl<T: Encodable> Encodable for Option<&mut dyn ExactSizeIterator<Item = T>> {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
encode_vector_from_iter(encoder, offset, recursion_depth, self.as_mut().map(|x| &mut **x))
}
}
impl_layout_forall_T!(Option<Vec<T>>, align: 8, size: 16);
impl<T: Encodable> Encodable for Option<Vec<T>> {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
encode_vector(encoder, offset, recursion_depth, self.as_deref_mut())
}
}
impl<T: Decodable> Decodable for Option<Vec<T>> {
fn new_empty() -> Self {
None
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
let was_some;
{
let vec = self.get_or_insert(Vec::new());
was_some = decode_vector(decoder, vec)?;
}
if !was_some {
*self = None
}
Ok(())
}
}
/// An shorthand macro for calling `Encodable::encode()` from generated code
/// with full parameters, without importing the `Encodable` trait.
/// This is intended to be used only by generated code.
#[doc(hidden)]
#[macro_export]
macro_rules! fidl_encode {
($val:expr, $encoder:expr, $offset:expr, $recursion_depth:expr) => {
$crate::encoding::Encodable::encode($val, $encoder, $offset, $recursion_depth)
};
}
/// A shorthand macro for calling `Decodable::decode()` on a type
/// without importing the `Decodable` trait.
/// This is intended to be used only by generated code.
#[doc(hidden)]
#[macro_export]
macro_rules! fidl_decode {
($val:expr, $decoder:expr) => {
$crate::encoding::Decodable::decode($val, $decoder)
};
}
/// A shorthand macro for calling `Decodable::new_empty()` on a type
/// without importing the `Decodable` trait.
#[macro_export]
macro_rules! fidl_new_empty {
($type:ty) => {
<$type as $crate::encoding::Decodable>::new_empty()
};
}
/// Declare a bits type and implement the FIDL coding traits for it.
///
/// Example:
///
/// ```rust
/// fidl_bits!(MyBits (u32) { BAR = 5, BAZ = 6, });
///
/// // expands to:
///
/// bitflags! {
/// struct MyBits: u32 {
/// const BAR = 5;
/// const BAZ = 6;
/// }
/// }
///
/// impl Encodable for MyBits { ... }
/// impl Decodable for MyBits { ... }
/// ```
#[macro_export]
macro_rules! fidl_bits {
($name:ident ($prim_ty:ident) { $($key:ident = $value:expr,)* }) => {
$crate::bitflags! {
pub struct $name: $prim_ty {
$(
const $key = $value;
)*
}
}
impl $crate::encoding::Layout for $name {
fn inline_align(context: &$crate::encoding::Context) -> usize {
<$prim_ty as $crate::encoding::Layout>::inline_align(context)
}
fn inline_size(context: &$crate::encoding::Context) -> usize {
<$prim_ty as $crate::encoding::Layout>::inline_size(context)
}
}
impl $crate::encoding::Encodable for $name {
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder<'_>, offset: usize, recursion_depth: usize)
-> ::std::result::Result<(), $crate::Error>
{
$crate::fidl_encode!(&mut self.bits, encoder, offset, recursion_depth)
}
}
impl $crate::encoding::Decodable for $name {
fn new_empty() -> Self {
Self::empty()
}
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder<'_>)
-> ::std::result::Result<(), $crate::Error>
{
let mut prim = $crate::fidl_new_empty!($prim_ty);
$crate::fidl_decode!(&mut prim, decoder)?;
*self = Self::from_bits(prim).ok_or($crate::Error::Invalid)?;
Ok(())
}
}
}
}
/// Declare an enum type and implement the FIDL coding traits for it.
///
/// Example:
///
/// ```rust
/// fidl_enum!(MyEnum (u32) { BAR = 5, BAZ = 6, });
///
/// // expands to:
///
/// #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
/// #[repr($prim_ty)]
/// pub enum MyEnum {
/// BAR = 5,
/// BAZ = 6,
/// }
///
/// impl MyEnum {
/// pub fn from_primitive(prim: u32) -> Option<Self> { ... }
/// pub fn into_primitive(self) -> u32 { ... }
/// }
///
/// impl Encodable for MyEnum { ... }
/// impl Decodable for MyEnum { ... }
/// ```
#[macro_export]
macro_rules! fidl_enum {
($name:ident ($prim_ty:ident) { $($key:ident = $value:expr,)* }) => {
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr($prim_ty)]
pub enum $name {
$(
$key = $value,
)*
}
impl $name {
pub fn from_primitive(prim: $prim_ty) -> Option<Self> {
match prim {
$(
$value => Some($name::$key),
)*
_ => None,
}
}
pub fn into_primitive(self) -> $prim_ty {
self as $prim_ty
}
}
impl $crate::encoding::Layout for $name {
fn inline_align(context: &$crate::encoding::Context) -> usize {
<$prim_ty as $crate::encoding::Layout>::inline_align(context)
}
fn inline_size(context: &$crate::encoding::Context) -> usize {
<$prim_ty as $crate::encoding::Layout>::inline_size(context)
}
}
impl $crate::encoding::Encodable for $name {
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder<'_>, offset: usize, recursion_depth: usize)
-> ::std::result::Result<(), $crate::Error>
{
$crate::fidl_encode!(&mut (*self as $prim_ty), encoder, offset, recursion_depth)
}
}
impl $crate::encoding::Decodable for $name {
fn new_empty() -> Self {
// Returns the first declared variant
#![allow(unreachable_code)]
$(
return $name::$key;
)*
panic!("new_empty called on enum with no variants")
}
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder<'_>)
-> ::std::result::Result<(), $crate::Error>
{
let mut prim = $crate::fidl_new_empty!($prim_ty);
$crate::fidl_decode!(&mut prim, decoder)?;
*self = Self::from_primitive(prim).ok_or($crate::Error::Invalid)?;
Ok(())
}
}
}
}
impl_layout!(Handle, align: 4, size: 4);
impl Encodable for Handle {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
ALLOC_PRESENT_U32.encode(encoder, offset, recursion_depth)?;
let handle = take_handle(self);
encoder.handles.push(handle);
Ok(())
}
}
impl Decodable for Handle {
fn new_empty() -> Self {
Handle::invalid()
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
let mut present: u32 = 0;
present.decode(decoder)?;
match present {
ALLOC_ABSENT_U32 => return Err(Error::NotNullable),
ALLOC_PRESENT_U32 => {}
_ => return Err(Error::Invalid),
}
*self = decoder.take_handle()?;
Ok(())
}
}
impl_layout!(Option<Handle>, align: 4, size: 4);
impl Encodable for Option<Handle> {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
match self {
Some(handle) => handle.encode(encoder, offset, recursion_depth),
None => ALLOC_ABSENT_U32.encode(encoder, offset, recursion_depth),
}
}
}
impl Decodable for Option<Handle> {
fn new_empty() -> Self {
None
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
let mut present: u32 = 0;
present.decode(decoder)?;
match present {
ALLOC_ABSENT_U32 => {
*self = None;
Ok(())
}
ALLOC_PRESENT_U32 => {
*self = Some(decoder.take_handle()?);
Ok(())
}
_ => Err(Error::Invalid),
}
}
}
/// A macro for implementing the `Encodable` and `Decodable` traits for a type
/// which implements the `fuchsia_zircon::HandleBased` trait.
// TODO(cramertj) replace when specialization is stable
#[macro_export]
macro_rules! handle_based_codable {
($($ty:ident$(:- <$($generic:ident,)*>)*, )*) => { $(
impl<$($($generic,)*)*> $crate::encoding::Layout for $ty<$($($generic,)*)*> {
fn inline_align(_context: &$crate::encoding::Context) -> usize { 4 }
fn inline_size(_context: &$crate::encoding::Context) -> usize { 4 }
}
impl<$($($generic,)*)*> $crate::encoding::Encodable for $ty<$($($generic,)*)*> {
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder<'_>, offset: usize, recursion_depth: usize)
-> $crate::Result<()>
{
let mut handle = $crate::encoding::take_handle(self);
$crate::fidl_encode!(&mut handle, encoder, offset, recursion_depth)
}
}
impl<$($($generic,)*)*> $crate::encoding::Decodable for $ty<$($($generic,)*)*> {
fn new_empty() -> Self {
<$ty<$($($generic,)*)*> as $crate::handle::HandleBased>::from_handle($crate::handle::Handle::invalid())
}
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder<'_>)
-> $crate::Result<()>
{
let mut handle = $crate::handle::Handle::invalid();
$crate::fidl_decode!(&mut handle, decoder)?;
*self = <$ty<$($($generic,)*)*> as $crate::handle::HandleBased>::from_handle(handle);
Ok(())
}
}
impl<$($($generic,)*)*> $crate::encoding::Layout for Option<$ty<$($($generic,)*)*>> {
fn inline_align(_context: &$crate::encoding::Context) -> usize { 4 }
fn inline_size(_context: &$crate::encoding::Context) -> usize { 4 }
}
impl<$($($generic,)*)*> $crate::encoding::Encodable for Option<$ty<$($($generic,)*)*>> {
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder<'_>, offset: usize, recursion_depth: usize)
-> $crate::Result<()>
{
match self {
Some(handle) => $crate::fidl_encode!(handle, encoder, offset, recursion_depth),
None => $crate::fidl_encode!(&mut $crate::encoding::ALLOC_ABSENT_U32, encoder, offset, recursion_depth),
}
}
}
impl<$($($generic,)*)*> $crate::encoding::Decodable for Option<$ty<$($($generic,)*)*>> {
fn new_empty() -> Self { None }
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder<'_>) -> $crate::Result<()> {
let mut handle: Option<$crate::handle::Handle> = None;
$crate::fidl_decode!(&mut handle, decoder)?;
*self = handle.map(Into::into);
Ok(())
}
}
)* }
}
impl Layout for zx_status::Status {
fn inline_size(_context: &Context) -> usize {
mem::size_of::<zx_status::zx_status_t>()
}
fn inline_align(_context: &Context) -> usize {
mem::size_of::<zx_status::zx_status_t>()
}
}
impl Encodable for zx_status::Status {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
_recursion_depth: usize,
) -> Result<()> {
type Raw = zx_status::zx_status_t;
encoder.buf[offset..offset + mem::size_of::<Raw>()]
.copy_from_slice(&self.into_raw().to_le_bytes());
Ok(())
}
}
impl Decodable for zx_status::Status {
fn new_empty() -> Self {
Self::from_raw(0)
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
type Raw = zx_status::zx_status_t;
const SIZE: usize = mem::size_of::<Raw>();
let offset = decoder.next_offset(SIZE);
match <[u8; SIZE]>::try_from(&decoder.buf[offset..offset + SIZE]) {
Ok(array) => {
*self = Self::from_raw(Raw::from_le_bytes(array));
Ok(())
}
Err(_) => Err(Error::OutOfRange),
}
}
}
/// The body of a FIDL Epitaph
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct EpitaphBody {
/// The error status
pub error: zx_status::Status,
}
impl Layout for EpitaphBody {
fn inline_align(context: &Context) -> usize {
<zx_status::Status as Layout>::inline_align(context)
}
fn inline_size(context: &Context) -> usize {
<zx_status::Status as Layout>::inline_size(context)
}
}
impl Encodable for EpitaphBody {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
self.error.encode(encoder, offset, recursion_depth)
}
}
impl Decodable for EpitaphBody {
fn new_empty() -> Self {
Self { error: zx_status::Status::new_empty() }
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
self.error.decode(decoder)
}
}
macro_rules! handle_encoding {
($x:tt, $availability:ident) => {
type $x = crate::handle::$x;
handle_based_codable![$x,];
};
}
invoke_for_handle_types!(handle_encoding);
/// A trait that provides automatic support for nullable types.
///
/// Types that implement this trait will automatically receive `Encodable` and
/// `Decodable` implementations for `Option<Box<Self>>` (nullable owned type),
/// and `Encodable` for `Option<&mut Self>` (nullable borrowed type).
pub trait Autonull: Encodable + Decodable {
/// Returns true if the type is naturally able to be nullable.
///
/// Types that return true (e.g., xunions) encode `Some(x)` the same as `x`,
/// and `None` as a full bout of inline zeros. Types that return false
/// (e.g., structs) encode `Some(x)` as `ALLOC_PRESENT_U64` with an
/// out-of-line payload, and `None` as `ALLOC_ABSENT_U64`.
fn naturally_nullable(context: &Context) -> bool;
}
impl<T: Autonull> Layout for Option<&mut T> {
fn inline_align(context: &Context) -> usize {
if T::naturally_nullable(context) {
<T as Layout>::inline_align(context)
} else {
8
}
}
fn inline_size(context: &Context) -> usize {
if T::naturally_nullable(context) {
<T as Layout>::inline_size(context)
} else {
8
}
}
}
impl<T: Autonull> Encodable for Option<&mut T> {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
if T::naturally_nullable(encoder.context) {
match self {
Some(x) => x.encode(encoder, offset, recursion_depth),
None => {
// This is an empty xunion.
encoder.padding(offset, 24);
Ok(())
}
}
} else {
match self {
Some(x) => {
ALLOC_PRESENT_U64.encode(encoder, offset, recursion_depth)?;
encoder.write_out_of_line(
encoder.inline_size_of::<T>(),
recursion_depth,
|encoder, offset, recursion_depth| {
x.encode(encoder, offset, recursion_depth)
},
)
}
None => ALLOC_ABSENT_U64.encode(encoder, offset, recursion_depth),
}
}
}
}
impl<T: Autonull> Layout for Option<Box<T>> {
fn inline_align(context: &Context) -> usize {
<Option<&mut T> as Layout>::inline_align(context)
}
fn inline_size(context: &Context) -> usize {
<Option<&mut T> as Layout>::inline_size(context)
}
}
impl<T: Autonull> Encodable for Option<Box<T>> {
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
// Call Option<&mut T>'s encode method.
self.as_deref_mut().encode(encoder, offset, recursion_depth)
}
}
// Presence indicators always include at least one non-zero byte,
// while absence indicators should always be entirely zeros.
fn check_for_presence(decoder: &mut Decoder<'_>, inline_size: usize) -> Result<bool> {
Ok(decoder.buf[decoder.offset..decoder.offset + inline_size].iter().any(|byte| *byte != 0))
}
impl<T: Autonull> Decodable for Option<Box<T>> {
fn new_empty() -> Self {
None
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
if T::naturally_nullable(decoder.context) {
let inline_size = decoder.inline_size_of::<T>();
let present = check_for_presence(decoder, inline_size)?;
if present {
self.get_or_insert_with(|| Box::new(T::new_empty())).decode(decoder)
} else {
*self = None;
// Eat the full `inline_size` bytes including the
// ALLOC_ABSENT that we only peeked at before
decoder.skip_padding(inline_size)?;
Ok(())
}
} else {
let mut present: u64 = 0;
present.decode(decoder)?;
match present {
ALLOC_PRESENT_U64 => decoder
.read_out_of_line(decoder.inline_size_of::<T>(), |decoder| {
self.get_or_insert_with(|| Box::new(T::new_empty())).decode(decoder)
}),
ALLOC_ABSENT_U64 => {
*self = None;
Ok(())
}
_ => Err(Error::Invalid),
}
}
}
}
/// A macro which implements the FIDL `Encodable` and `Decodable` traits
/// for an existing struct.
#[macro_export]
macro_rules! fidl_struct {
(
name: $name:ty,
members: [$(
$member_name:ident {
ty: $member_ty:ty,
offset_v1: $member_offset_v1:expr,
},
)*],
size_v1: $size_v1:expr,
align_v1: $align_v1:expr,
) => {
impl $crate::encoding::Layout for $name {
fn inline_align(_context: &$crate::encoding::Context) -> usize {
$align_v1
}
fn inline_size(_context: &$crate::encoding::Context) -> usize {
$size_v1
}
}
impl $crate::encoding::Encodable for $name {
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder<'_>, offset: usize, recursion_depth: usize) -> $crate::Result<()> {
let mut padding_start = 0;
$(
encoder.padding(offset + padding_start, $member_offset_v1 - padding_start);
$crate::fidl_encode!(&mut self.$member_name, encoder, offset + $member_offset_v1, recursion_depth)?;
padding_start = $member_offset_v1 + encoder.inline_size_of::<$member_ty>();
)*
encoder.padding(offset + padding_start, encoder.inline_size_of::<Self>() - padding_start);
Ok(())
}
}
impl $crate::encoding::Decodable for $name {
fn new_empty() -> Self {
Self {
$(
$member_name: $crate::fidl_new_empty!($member_ty),
)*
}
}
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder<'_>) -> $crate::Result<()> {
let mut cur_offset = 0;
$(
// Skip to the start of the next field
let member_offset = $member_offset_v1;
decoder.skip_padding(member_offset - cur_offset)?;
cur_offset = member_offset;
$crate::fidl_decode!(&mut self.$member_name, decoder)?;
cur_offset += decoder.inline_size_of::<$member_ty>();
)*
// Skip to the end of the struct's size
decoder.skip_padding(decoder.inline_size_of::<Self>() - cur_offset)?;
Ok(())
}
}
impl $crate::encoding::Autonull for $name {
fn naturally_nullable(_context: &$crate::encoding::Context) -> bool {
false
}
}
}
}
/// A macro which implements the FIDL `Encodable` and `Decodable` traits
/// for an existing struct by doing a direct copy using zerocopy::AsBytes.
#[macro_export]
macro_rules! fidl_struct_copy {
(
name: $name:ty,
members: [$(
$member_name:ident {
ty: $member_ty:ty,
offset_v1: $member_offset_v1:expr,
},
)*],
size_v1: $size_v1:expr,
align_v1: $align_v1:expr,
) => {
impl $crate::encoding::Layout for $name {
fn inline_align(_context: &$crate::encoding::Context) -> usize {
$align_v1
}
fn inline_size(_context: &$crate::encoding::Context) -> usize {
$size_v1
}
fn slice_as_bytes(slice: &mut [Self]) -> Option<&mut [u8]> {
Some(zerocopy::AsBytes::as_bytes_mut(slice))
}
}
impl $crate::encoding::Encodable for $name {
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder<'_>, offset: usize, _recursion_depth: usize) -> $crate::Result<()> {
let bytes = zerocopy::AsBytes::as_bytes(self);
encoder.buf[offset..offset + bytes.len()].copy_from_slice(bytes);
Ok(())
}
}
impl $crate::encoding::Decodable for $name {
fn new_empty() -> Self {
Self {
$(
$member_name: $crate::fidl_new_empty!($member_ty),
)*
}
}
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder<'_>) -> $crate::Result<()> {
let bytes: &mut [u8] = zerocopy::AsBytes::as_bytes_mut(self);
let size = bytes.len();
let offset = decoder.next_offset(size);
bytes.copy_from_slice(&decoder.buf[offset..offset + size]);
Ok(())
}
}
impl $crate::encoding::Autonull for $name {
fn naturally_nullable(_context: &$crate::encoding::Context) -> bool {
false
}
}
}
}
/// A macro which creates an empty struct and implements the FIDL `Encodable` and `Decodable`
/// traits for it.
#[macro_export]
macro_rules! fidl_empty_struct {
($(#[$attrs:meta])* $name:ident) => {
$(#[$attrs])*
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct $name;
impl $crate::encoding::Layout for $name {
fn inline_align(_context: &$crate::encoding::Context) -> usize { 1 }
fn inline_size(_context: &$crate::encoding::Context) -> usize { 1 }
}
impl $crate::encoding::Encodable for $name {
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder<'_>, offset: usize, recursion_depth: usize) -> $crate::Result<()> {
$crate::fidl_encode!(&mut 0u8, encoder, offset, recursion_depth)
}
}
impl $crate::encoding::Decodable for $name {
fn new_empty() -> Self { $name }
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder<'_>) -> $crate::Result<()> {
let mut x = 0u8;
$crate::fidl_decode!(&mut x, decoder)?;
if x == 0 {
Ok(())
} else {
Err($crate::Error::Invalid)
}
}
}
impl $crate::encoding::Autonull for $name {
fn naturally_nullable(_context: &$crate::encoding::Context) -> bool {
false
}
}
}
}
/// Encode the provided value behind a FIDL "envelope".
pub fn encode_in_envelope(
val: &mut Option<&mut dyn Encodable>,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
// u32 num_bytes
// u32 num_handles
// 64-bit presence indicator
match val {
Some(x) => {
// Start at offset 8 because we write the first 8 bytes (number of bytes and number
// number of handles, both u32) at the end.
ALLOC_PRESENT_U64.encode(encoder, offset + 8, recursion_depth)?;
let bytes_before = encoder.buf.len();
let handles_before = encoder.handles.len();
encoder.write_out_of_line(
x.inline_size(encoder.context),
recursion_depth,
|e, offset, recursion_depth| x.encode(e, offset, recursion_depth),
)?;
let mut bytes_written = (encoder.buf.len() - bytes_before) as u32;
let mut handles_written = (encoder.handles.len() - handles_before) as u32;
bytes_written.encode(encoder, offset, recursion_depth)?;
handles_written.encode(encoder, offset + 4, recursion_depth)?;
}
None => {
0u32.encode(encoder, offset, recursion_depth)?; // num_bytes
0u32.encode(encoder, offset + 4, recursion_depth)?; // num_handles
ALLOC_ABSENT_U64.encode(encoder, offset + 8, recursion_depth)?;
}
}
Ok(())
}
/// Decodes an unknown field in a table. If it is non-empty, also skips over the
/// unknown out-of-line payload.
pub fn decode_unknown_table_field(decoder: &mut Decoder<'_>) -> Result<()> {
let mut num_bytes: u32 = 0;
num_bytes.decode(decoder)?;
let mut num_handles: u32 = 0;
num_handles.decode(decoder)?;
let mut present: u64 = 0;
present.decode(decoder)?;
match present {
ALLOC_PRESENT_U64 => decoder.read_out_of_line(num_bytes as usize, |decoder| {
decoder.next_offset(num_bytes as usize);
for _ in 0..num_handles {
decoder.take_handle()?;
}
Ok(())
}),
ALLOC_ABSENT_U64 => {
if num_bytes != 0 {
Err(Error::UnexpectedNullRef)
} else {
Ok(())
}
}
_ => Err(Error::Invalid),
}
}
/// A macro which implements the table empty constructor and the FIDL `Encodable` and `Decodable`
/// traits for an existing struct whose fields are all `Option`s and may or may not appear in the
/// wire-format representation.
#[macro_export]
macro_rules! fidl_table {
(
name: $name:ty,
members: {$(
// NOTE: members must be in order from lowest to highest ordinal
$member_name:ident {
ty: $member_ty:ty,
ordinal: $ordinal:expr,
},
)*},
) => {
impl $name {
/// Generates an empty table, with every field set to `None`.
pub fn empty() -> Self {
Self {$(
$member_name: None,
)*}
}
}
impl $crate::encoding::Layout for $name {
fn inline_align(_context: &$crate::encoding::Context) -> usize { 8 }
fn inline_size(_context: &$crate::encoding::Context) -> usize { 16 }
}
impl $crate::encoding::Encodable for $name {
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder<'_>, offset: usize, recursion_depth: usize) -> $crate::Result<()> {
let members: &mut [(u64, Option<&mut dyn $crate::encoding::Encodable>)] = &mut [$(
($ordinal, self.$member_name.as_mut().map(|x| x as &mut dyn $crate::encoding::Encodable)),
)*];
// Cut off the `None` elements at the tail of the table
let last_some_index = members.iter().rposition(|x| x.1.is_some());
let members = if let Some(i) = last_some_index {
&mut members[..(i + 1)]
} else {
&mut []
};
// Vector header
let max_ordinal = members.last().map(|v| v.0).unwrap_or(0);
(max_ordinal as u64).encode(encoder, offset, recursion_depth)?;
$crate::encoding::ALLOC_PRESENT_U64.encode(encoder, offset + 8, recursion_depth)?;
let bytes_len = (max_ordinal as usize) * 16;
encoder.write_out_of_line(bytes_len, recursion_depth, |encoder, offset, recursion_depth| {
let mut prev_end_offset: usize = 0;
for (ref ordinal, encodable) in members.iter_mut() {
// Write at offset+(ordinal-1)*16, since ordinals are one-based and envelopes are 16 bytes.
let cur_offset = (*ordinal as usize - 1) * 16;
// Zero reserved fields.
encoder.padding(offset + prev_end_offset, cur_offset - prev_end_offset);
// Encode present field.
$crate::encoding::encode_in_envelope(encodable, encoder, offset + cur_offset, recursion_depth)?;
prev_end_offset = cur_offset + 16;
}
Ok(())
})
}
}
impl $crate::encoding::Decodable for $name {
fn new_empty() -> Self {
Self::empty()
}
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder<'_>) -> $crate::Result<()> {
// Decode envelope vector header
let mut len: u64 = 0;
$crate::fidl_decode!(&mut len, decoder)?;
let mut present: u64 = 0;
$crate::fidl_decode!(&mut present, decoder)?;
if present != $crate::encoding::ALLOC_PRESENT_U64 {
return Err($crate::Error::Invalid);
}
let len = len as usize;
let bytes_len = len * 16; // envelope inline_size is 16
decoder.read_out_of_line(bytes_len, |decoder| {
// Decode the envelope for each type.
// u32 num_bytes
// u32_num_handles
// 64-bit presence indicator
let mut _next_ordinal_to_read = 0;
$(
_next_ordinal_to_read += 1;
if decoder.is_empty() {
// The remaining fields have been omitted, so set them to None
self.$member_name = None;
} else {
// Decode unknown envelopes for gaps in ordinals.
while _next_ordinal_to_read < $ordinal {
$crate::encoding::decode_unknown_table_field(decoder)?;
_next_ordinal_to_read += 1;
}
let mut num_bytes: u32 = 0;
$crate::fidl_decode!(&mut num_bytes, decoder)?;
let mut num_handles: u32 = 0;
$crate::fidl_decode!(&mut num_handles, decoder)?;
let mut present: u64 = 0;
$crate::fidl_decode!(&mut present, decoder)?;
let next_out_of_line = decoder.next_out_of_line();
let handles_before = decoder.remaining_handles();
match present {
$crate::encoding::ALLOC_PRESENT_U64 => {
decoder.read_out_of_line(
decoder.inline_size_of::<$member_ty>(),
|d| {
let val_ref =
self.$member_name.get_or_insert_with(
|| $crate::fidl_new_empty!($member_ty));
$crate::fidl_decode!(val_ref, d)?;
Ok(())
},
)?;
}
$crate::encoding::ALLOC_ABSENT_U64 => {
if num_bytes != 0 {
return Err($crate::Error::UnexpectedNullRef);
}
self.$member_name = None;
}
_ => return Err($crate::Error::Invalid),
}
if decoder.next_out_of_line() != (next_out_of_line + (num_bytes as usize)) {
return Err($crate::Error::Invalid);
}
if handles_before != (decoder.remaining_handles() + (num_handles as usize)) {
return Err($crate::Error::Invalid);
}
}
)*
// Decode the remaining unknown envelopes.
while !decoder.is_empty() {
$crate::encoding::decode_unknown_table_field(decoder)?;
}
Ok(())
})
}
}
}
}
/// Decodes the inline portion of a xunion. Returns (ordinal, num_bytes, num_handles).
pub fn decode_xunion_inline_portion(decoder: &mut Decoder) -> Result<(u64, u32, u32)> {
let mut ordinal: u64 = 0;
ordinal.decode(decoder)?;
let mut num_bytes: u32 = 0;
num_bytes.decode(decoder)?;
let mut num_handles: u32 = 0;
num_handles.decode(decoder)?;
let mut present: u64 = 0;
present.decode(decoder)?;
if present != ALLOC_PRESENT_U64 {
return Err(Error::Invalid);
}
Ok((ordinal, num_bytes, num_handles))
}
impl<O, E> Layout for std::result::Result<O, E>
where
O: Layout,
E: Layout,
{
fn inline_align(_context: &Context) -> usize {
8
}
fn inline_size(_context: &Context) -> usize {
24
}
}
impl<O, E> Encodable for std::result::Result<O, E>
where
O: Encodable,
E: Encodable,
{
fn encode(
&mut self,
encoder: &mut Encoder<'_>,
offset: usize,
recursion_depth: usize,
) -> Result<()> {
match self {
Ok(val) => {
// Encode success ordinal
1u64.encode(encoder, offset, recursion_depth)?;
// If the inline size is 0, meaning the type is (),
// encode a zero byte instead because () in this context
// means an empty struct, not an absent payload.
if encoder.inline_size_of::<O>() == 0 {
encode_in_envelope(&mut Some(&mut 0u8), encoder, offset + 8, recursion_depth)
} else {
encode_in_envelope(&mut Some(val), encoder, offset + 8, recursion_depth)
}
}
Err(val) => {
// Encode error ordinal
2u64.encode(encoder, offset, recursion_depth)?;
encode_in_envelope(&mut Some(val), encoder, offset + 8, recursion_depth)
}
}
}
}
impl<O, E> Decodable for std::result::Result<O, E>
where
O: Decodable,
E: Decodable,
{
fn new_empty() -> Self {
Ok(<O as Decodable>::new_empty())
}
fn decode(&mut self, decoder: &mut Decoder<'_>) -> Result<()> {
let (ordinal, _, _) = decode_xunion_inline_portion(decoder)?;
let member_inline_size = match ordinal {
1 => {
// If the inline size is 0, meaning the type is (), use an inline
// size of 1 instead because () in this context means an empty
// struct, not an absent payload.
cmp::max(1, decoder.inline_size_of::<O>())
}
2 => decoder.inline_size_of::<E>(),
_ => return Err(Error::UnknownUnionTag),
};
decoder.read_out_of_line(member_inline_size, |decoder| {
match ordinal {
1 => {
if let Ok(_) = self {
// Do nothing, read the value into the object
} else {
// Initialize `self` to the right variant
*self = Ok(fidl_new_empty!(O));
}
if let Ok(val) = self {
// If the inline size is 0, then the type is ().
// () has a different wire-format representation in
// a result vs outside of a result, so special case
// decode.
if decoder.inline_size_of::<O>() == 0 {
decoder.skip_padding(1)
} else {
val.decode(decoder)
}
} else {
unreachable!()
}
}
2 => {
if let Err(_) = self {
// Do nothing, read the value into the object
} else {
// Initialize `self` to the right variant
*self = Err(fidl_new_empty!(E));
}
if let Err(val) = self {
val.decode(decoder)
} else {
unreachable!()
}
}
// Should be unreachable, since we already checked above.
ordinal => panic!("unexpected ordinal {:?}", ordinal),
}
})
}
}
/// A macro which declares a new FIDL xunion as a Rust enum and implements the
/// FIDL encoding and decoding traits for it.
#[macro_export]
macro_rules! fidl_xunion {
(
$(#[$attrs:meta])*
name: $name:ident,
members: [$(
$(#[$member_docs:meta])*
$member_name:ident {
ty: $member_ty:ty,
ordinal: $member_ordinal:expr,
},
)*],
// Flexible xunions only: name of the unknown variant.
$( unknown_member: $unknown_name:ident, )?
) => {
$( #[$attrs] )*
pub enum $name {
$(
$(#[$member_docs])*
$member_name ( $member_ty ),
)*
$(
#[doc(hidden)]
$unknown_name {
ordinal: u64,
bytes: Vec<u8>,
handles: Vec<$crate::handle::Handle>,
},
)?
}
impl $name {
fn ordinal(&self) -> u64 {
match *self {
$(
$name::$member_name(_) => $member_ordinal,
)*
$(
$name::$unknown_name { ordinal, .. } => ordinal,
)?
}
}
}
impl $crate::encoding::Layout for $name {
fn inline_align(_context: &$crate::encoding::Context) -> usize { 8 }
fn inline_size(_context: &$crate::encoding::Context) -> usize { 24 }
}
impl $crate::encoding::Encodable for $name {
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder<'_>, offset: usize, recursion_depth: usize) -> $crate::Result<()> {
let mut ordinal = self.ordinal();
// Encode ordinal
$crate::fidl_encode!(&mut ordinal, encoder, offset, recursion_depth)?;
match self {
$(
$name::$member_name ( val ) => $crate::encoding::encode_in_envelope(&mut Some(val), encoder, offset+8, recursion_depth),
)*
$(
$name::$unknown_name { ordinal: _, bytes, handles } => {
// Throw the raw data from the unrecognized variant
// back onto the wire. This will allow correct proxies even in
// the event that they don't yet recognize this union variant.
$crate::fidl_encode!(&mut (bytes.len() as u32), encoder, offset + 8, recursion_depth)?;
$crate::fidl_encode!(&mut (handles.len() as u32), encoder, offset + 12, recursion_depth)?;
$crate::fidl_encode!(
&mut $crate::encoding::ALLOC_PRESENT_U64, encoder, offset + 16, recursion_depth
)?;
$crate::encoding::Encoder::check_recursion_depth(recursion_depth + 1)?;
encoder.append_bytes(bytes);
encoder.append_handles(handles);
Ok(())
},
)?
}
}
}
impl $crate::encoding::Decodable for $name {
fn new_empty() -> Self {
#![allow(unreachable_code)]
$(
return $name::$member_name($crate::fidl_new_empty!($member_ty));
)*
$(
$name::$unknown_name { ordinal: 0, bytes: vec![], handles: vec![] }
)?
}
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder<'_>) -> $crate::Result<()> {
#![allow(irrefutable_let_patterns, unused)]
let (ordinal, num_bytes, num_handles) = $crate::encoding::decode_xunion_inline_portion(decoder)?;
let member_inline_size = match ordinal {
$(
$member_ordinal => decoder.inline_size_of::<$member_ty>(),
)*
$(
_ => {
// We need the expansion to refer to $unknown_name,
// so just create and discard it as a string.
stringify!($unknown_name);
// Flexible xunion: unknown payloads are considered
// a wholly-inline string of bytes.
num_bytes as usize
}
)?
// Strict xunion: reject unknown ordinals.
_ => return Err($crate::Error::UnknownUnionTag),
};
decoder.read_out_of_line(member_inline_size, |decoder| {
match ordinal {
$(
$member_ordinal => {
if let $name::$member_name(_) = self {
// Do nothing, read the value into the object
} else {
// Initialize `self` to the right variant
*self = $name::$member_name(
$crate::fidl_new_empty!($member_ty)
);
}
if<