blob: e67969da07bf7aa6c17054cfabc0dd881007b961 [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.
//! Encoding2 contains functions and traits for FIDL2 encoding and decoding.
use {
crate::{Error, Result},
byteorder::{ByteOrder, LittleEndian},
fuchsia_zircon::{
self as zx,
HandleBased,
},
std::{mem, ptr, str, u32, u64},
};
/// Rounds `x` up if necessary so that it is a multiple of `align`.
pub fn round_up_to_align(x: usize, align: usize) -> usize {
if align == 0 {
0
} else {
((x + align - 1) / align) * align
}
}
/// Split off the first element from a slice.
fn split_off_first<'a, T>(slice: &mut &'a [T]) -> Result<&'a T> {
split_off_front(slice, 1).map(|res| &res[0])
}
/// 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` bytes from `slice`.
fn split_off_front<'a, T>(slice: &mut &'a [T], n: usize) -> Result<&'a [T]> {
if n > slice.len() {
return Err(Error::OutOfRange);
}
let original = take_slice(slice);
let (head, tail) = original.split_at(n);
*slice = tail;
Ok(head)
}
/// 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 slice.
fn take_slice<'a, T>(x: &mut &'a [T]) -> &'a [T] {
mem::replace(x, &mut [])
}
/// 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) -> zx::Handle {
let invalid = T::from_handle(zx::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;
/// Encoding state
#[derive(Debug)]
pub struct Encoder<'a> {
/// Offset at which to write new objects.
offset: usize,
/// The maximum remaining number of recursive steps.
remaining_depth: usize,
/// 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<zx::Handle>,
}
/// Decoding state
#[derive(Debug)]
pub struct Decoder<'a> {
/// The maximum remaining number of recursive steps.
remaining_depth: usize,
/// Buffer from which to read data.
buf: &'a [u8],
/// Buffer from which to read out-of-line data.
out_of_line_buf: &'a [u8],
/// Buffer from which to read handles.
handles: &'a mut [zx::Handle],
}
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<zx::Handle>,
x: &mut T
) -> Result<()>
{
let inline_size = round_up_to_align(x.inline_size(), 8);
buf.truncate(0);
buf.resize(inline_size, 0);
handles.truncate(0);
let mut encoder = Encoder {
offset: 0,
remaining_depth: MAX_RECURSION,
buf,
handles,
};
x.encode(&mut encoder)
}
/// Runs the provided closure at at the next recursion depth level,
/// erroring if the maximum recursion limit has been reached.
pub fn recurse<F, R>(&mut self, f: F) -> Result<R>
where F: FnOnce(&mut Encoder) -> Result<R>
{
if self.remaining_depth == 0 {
return Err(Error::MaxRecursionDepth);
}
self.remaining_depth -= 1;
let res = f(self)?;
self.remaining_depth += 1;
Ok(res)
}
/// Returns a slice of the next `len` bytes after `offset` and increases `offset` by `len`.
pub fn next_slice(&mut self, len: usize) -> Result<&mut [u8]> {
let ret = self.buf.get_mut(self.offset..(self.offset + len)).ok_or(Error::OutOfRange)?;
self.offset += len;
Ok(ret)
}
/// Runs the provided closure inside an encoder modified
/// to write the data out-of-line.
///
/// Once the closure has completed, this function resets the offset
/// to where it was at the beginning of the call.
pub fn write_out_of_line<F>(&mut self, len: usize, f: F) -> Result<()>
where F: FnOnce(&mut Encoder) -> Result<()>
{
let old_offset = self.offset;
self.offset = self.buf.len();
// Create space for the new data
self.buf.resize(self.offset + round_up_to_align(len, 8), 0);
f(self)?;
self.offset = old_offset;
Ok(())
}
}
impl<'a> Decoder<'a> {
/// FIDL2-decodes a value of type `T` from the provided data and handle buffers.
pub fn decode_into<T: Decodable>(
buf: &'a [u8],
handles: &'a mut [zx::Handle],
value: &mut T,
) -> Result<()>
{
let out_of_line_offset = round_up_to_align(T::inline_size(), 8);
if buf.len() < out_of_line_offset {
return Err(Error::OutOfRange);
}
let (buf, out_of_line_buf) = buf.split_at(out_of_line_offset);
let mut decoder = Decoder {
remaining_depth: MAX_RECURSION,
buf,
out_of_line_buf,
handles,
};
value.decode(&mut decoder)
}
/// Runs the provided closure at at the next recursion depth level,
/// erroring if the maximum recursion limit has been reached.
pub fn recurse<F, R>(&mut self, f: F) -> Result<R>
where F: FnOnce(&mut Decoder) -> Result<R>
{
if self.remaining_depth == 0 {
return Err(Error::MaxRecursionDepth);
}
self.remaining_depth -= 1;
let res = f(self)?;
self.remaining_depth += 1;
Ok(res)
}
/// Runs the provided closure inside an decoder modified
/// to read out-of-line data.
///
/// `absolute_offset` indicates the offset of the start of the out-of-line data to read,
/// relative to the original start of the buffer.
pub fn read_out_of_line<F, R>(&mut self, len: usize, f: F) -> Result<R>
where F: FnOnce(&mut Decoder) -> Result<R>
{
// Currently, out-of-line points here:
// [---------------------------------]
// ^---buf--^ ^-out-of-line--^ (slices)
//
// We want to shift so that `buf` points to the first `len` bytes in `out-of-line` that
// are aligned to `align`, and `old-buf` points to the previous value of `buf`:
//
// [---------------------------------]
// ^old--buf^ ^--buf--^^ool^
// We split off the first `len` bytes from `out_of_line`.
let new_buf = split_off_front(&mut self.out_of_line_buf, len)?;
// Split off any trailing bytes up to the alignment and discard them.
if len % 8 != 0 {
let trailer = 8 - (len % 8);
let _ = split_off_front(&mut self.out_of_line_buf, trailer)?;
}
// Store the current `buf` slice and shift the `buf` slice to point at the out-of-line data.
let old_buf = take_slice(&mut self.buf);
self.buf = new_buf;
let res = f(self);
// Set the current `buf` back to its original position.
//
// After this transformation, the final `Decoder` looks like this:
// [---------------------------------]
// ^---buf--^ ^ool^ (slices)
// ^out-of-line-advanced (index)
self.buf = old_buf;
res
}
/// Whether or not the current section of inline bytes has been fully read.
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
/// The number of out-of-line bytes not yet accounted for by a `read_out_of_line`
/// call.
pub fn remaining_out_of_line(&self) -> usize {
self.out_of_line_buf.len()
}
/// The number of handles that have not yet been consumed.
pub fn remaining_handles(&self) -> usize {
self.handles.len()
}
/// Returns a slice of the next `len` bytes to be decoded into and shifts the decoding buffer.
pub fn next_slice(&mut self, len: usize) -> Result<&[u8]> {
split_off_front(&mut self.buf, len)
}
/// Like `next_slice`, but doesn't remove the bytes from `Self`.
pub fn peek_slice(&mut self, len: usize) -> Result<&[u8]> {
self.buf.get(0..len).ok_or_else(|| std::process::abort())
}
/// Take the next handle from the `handles` list and shift the list down by one element.
pub fn take_handle(&mut self) -> Result<zx::Handle> {
split_off_first_mut(&mut self.handles).map(take_handle)
}
}
/// A type which can be FIDL2-encoded into a buffer.
pub trait Encodable {
/// Returns the minimum required alignment of the inline portion of the encoded object.
fn inline_align(&self) -> usize;
/// Returns the size of the inline portion of the encoded object.
fn inline_size(&self) -> usize;
/// Encode the object into the buffer.
/// Any handles stored in the object are swapped for `zx::Handle::INVALID`.
/// Calls to this function should ensure that `encoder.offset` is a multiple of `inline_size`.
/// Successful calls to this function should increase `encoder.offset` by `inline_size`.
fn encode(&mut self, encoder: &mut Encoder) -> Result<()>;
}
/// A type which can be FIDL2-decoded from a buffer.
pub trait Decodable {
/// Returns the minimum required alignment of the inline portion of the encoded object.
fn inline_align() -> usize where Self: Sized;
/// Returns the size of the inline portion of the encoded object.
fn inline_size() -> usize where Self: Sized;
/// Creates a new value of this type with an "empty" representation.
fn new_empty() -> Self where Self: Sized;
/// 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_codable_num { ($($prim_ty:ty => $reader:ident + $writer:ident,)*) => { $(
impl Encodable for $prim_ty {
fn inline_align(&self) -> usize { mem::size_of::<$prim_ty>() }
fn inline_size(&self) -> usize { mem::size_of::<$prim_ty>() }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
let slot = encoder.next_slice(mem::size_of::<Self>())?;
LittleEndian::$writer(slot, *self);
Ok(())
}
}
impl Decodable for $prim_ty {
fn new_empty() -> Self { 0 as $prim_ty }
fn inline_size() -> usize { mem::size_of::<$prim_ty>() }
fn inline_align() -> usize { mem::size_of::<$prim_ty>() }
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
let end = mem::size_of::<Self>();
let range = split_off_front(&mut decoder.buf, end)?;
*self = LittleEndian::$reader(range);
Ok(())
}
}
)* } }
impl_codable_num!(
u16 => read_u16 + write_u16,
u32 => read_u32 + write_u32,
u64 => read_u64 + write_u64,
i16 => read_i16 + write_i16,
i32 => read_i32 + write_i32,
i64 => read_i64 + write_i64,
f32 => read_f32 + write_f32,
f64 => read_f64 + write_f64,
);
impl Encodable for bool {
fn inline_align(&self) -> usize { 1 }
fn inline_size(&self) -> usize { 1 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
let slot = encoder.next_slice(1)?;
slot[0] = if *self { 1 } else { 0 };
Ok(())
}
}
impl Decodable for bool {
fn new_empty() -> Self { false }
fn inline_align() -> usize { 1 }
fn inline_size() -> usize { 1 }
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
let num = *split_off_first(&mut decoder.buf)?;
*self = match num {
0 => false,
1 => true,
_ => return Err(Error::Invalid),
};
Ok(())
}
}
impl Encodable for u8 {
fn inline_align(&self) -> usize { 1 }
fn inline_size(&self) -> usize { 1 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
let slot = encoder.next_slice(1)?;
slot[0] = *self;
Ok(())
}
}
impl Decodable for u8 {
fn new_empty() -> Self { 0 }
fn inline_align() -> usize { 1 }
fn inline_size() -> usize { 1 }
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
*self = *split_off_first(&mut decoder.buf)?;
Ok(())
}
}
impl Encodable for i8 {
fn inline_align(&self) -> usize { 1 }
fn inline_size(&self) -> usize { 1 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
let slot = encoder.next_slice(1)?;
slot[0] = *self as u8;
Ok(())
}
}
impl Decodable for i8 {
fn new_empty() -> Self { 0 }
fn inline_align() -> usize { 1 }
fn inline_size() -> usize { 1 }
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
*self = *split_off_first(&mut decoder.buf)? as i8;
Ok(())
}
}
fn encode_array<T: Encodable>(encoder: &mut Encoder, slice: &mut [T]) -> Result<()> {
encoder.recurse(|encoder| {
for item in slice {
item.encode(encoder)?;
}
Ok(())
})
}
fn decode_array<T: Decodable>(decoder: &mut Decoder, slice: &mut [T]) -> Result<()> {
decoder.recurse(|decoder| {
for item in slice {
item.decode(decoder)?;
}
Ok(())
})
}
macro_rules! impl_codable_for_fixed_array { ($($len:expr,)*) => { $(
impl<T: Encodable> Encodable for [T; $len] {
fn inline_align(&self) -> usize {
self.get(0).map(Encodable::inline_align).unwrap_or(0)
}
fn inline_size(&self) -> usize {
self.get(0).map(Encodable::inline_size).unwrap_or(0)
}
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encode_array(encoder, self)
}
}
impl<T: Decodable> Decodable for [T; $len] {
fn new_empty() -> Self {
unsafe {
// We wrap the `arr` in a `ManuallyDrop` to prevent it from
// being dropped during a failure partway through initialization.
let mut arr: mem::ManuallyDrop<[T; $len]> = mem::uninitialized();
let arr_ptr: *mut T = arr.as_mut_ptr();
for i in 0..$len {
ptr::write(arr_ptr.offset(i as isize), T::new_empty());
}
mem::ManuallyDrop::into_inner(arr)
}
}
fn inline_align() -> usize { T::inline_align() }
fn inline_size() -> usize { T::inline_size() * $len }
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
decode_array(decoder, self)
}
}
)* } }
// 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.
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.net
impl_codable_for_fixed_array!(256,);
fn encode_byte_slice(encoder: &mut Encoder, slice_opt: Option<&[u8]>) -> Result<()> {
match slice_opt {
None => encode_absent_vector(encoder),
Some(slice) => {
// Two u64: (len, present)
(slice.len() as u64).encode(encoder)?;
ALLOC_PRESENT_U64.encode(encoder)?;
encoder.write_out_of_line(slice.len(), |encoder| {
let slot = encoder.next_slice(slice.len())?;
slot.copy_from_slice(slice);
Ok(())
})
}
}
}
/// Encode an missing vector-like component.
pub fn encode_absent_vector(encoder: &mut Encoder) -> Result<()> {
0u64.encode(encoder)?;
ALLOC_ABSENT_U64.encode(encoder)
}
/// Encode an optional iterator over encodable elements into a FIDL vector-like representation.
pub fn encode_encodable_iter<Iter, T>(
encoder: &mut Encoder,
iter_opt: Option<Iter>,
) -> Result<()>
where
Iter: ExactSizeIterator<Item = T>,
T: Encodable,
{
match iter_opt {
None => encode_absent_vector(encoder),
Some(mut iter) => {
// Two u64: (len, present)
(iter.len() as u64).encode(encoder)?;
ALLOC_PRESENT_U64.encode(encoder)?;
let mut first = if let Some(first) = iter.next() {
first
} else {
return Ok(())
};
let bytes_len = (iter.len() + 1) * first.inline_size();
encoder.write_out_of_line(bytes_len, |encoder| {
encoder.recurse(|encoder| {
first.encode(encoder)?;
for mut item in iter {
item.encode(encoder)?;
}
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 Ok(false),
ALLOC_PRESENT_U64 => {},
_ => return Err(Error::Invalid),
};
let len = len as usize;
decoder.read_out_of_line(len, |decoder| {
string.truncate(0);
string.push_str(
str::from_utf8(decoder.buf)
.map_err(|_| Error::Utf8Error)?
);
Ok(true)
})
}
/// Attempts to decode a vec into `vec`, returning a `bool`
/// indicating whether or not a vec was present.
fn decode_vec<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 Ok(false),
ALLOC_PRESENT_U64 => {},
_ => return Err(Error::Invalid),
}
let len = len as usize;
let bytes_len = len * T::inline_size();
decoder.read_out_of_line(bytes_len, |decoder| {
decoder.recurse(|decoder| {
vec.truncate(0);
for _ in 0..len {
vec.push(T::new_empty());
// We just pushed an element on, so the `unwrap` will succeed.
vec.last_mut().unwrap().decode(decoder)?;
}
Ok(true)
})
})
}
impl<'a> Encodable for &'a str {
fn inline_align(&self) -> usize { 8 }
fn inline_size(&self) -> usize { 16 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encode_byte_slice(encoder, Some(self.as_bytes()))
}
}
impl Encodable for String {
fn inline_align(&self) -> usize { 8 }
fn inline_size(&self) -> usize { 16 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encode_byte_slice(encoder, Some(self.as_bytes()))
}
}
impl Decodable for String {
fn new_empty() -> Self {
String::new()
}
fn inline_align() -> usize { 8 }
fn inline_size() -> usize { 16 }
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
if decode_string(decoder, self)? {
Ok(())
} else {
Err(Error::NotNullable)
}
}
}
impl<'a> Encodable for Option<&'a str> {
fn inline_align(&self) -> usize { 8 }
fn inline_size(&self) -> usize { 16 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encode_byte_slice(encoder, self.as_ref().map(|x| x.as_bytes()))
}
}
impl Encodable for Option<String> {
fn inline_align(&self) -> usize { 8 }
fn inline_size(&self) -> usize { 16 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encode_byte_slice(encoder, self.as_ref().map(|x| x.as_bytes()))
}
}
impl Decodable for Option<String> {
fn new_empty() -> Self {
None
}
fn inline_align() -> usize { 8 }
fn inline_size() -> usize { 16 }
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<'a, 'b: 'a, T: Encodable> Encodable for
&'a mut ExactSizeIterator<Item = T>
{
fn inline_align(&self) -> usize { 8 }
fn inline_size(&self) -> usize { 16 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encode_encodable_iter(encoder, Some(self))
}
}
impl<'a, T: Encodable> Encodable for &'a mut [T] {
fn inline_align(&self) -> usize { 8 }
fn inline_size(&self) -> usize { 16 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encode_encodable_iter(encoder, Some(self.iter_mut()))
}
}
impl<T: Encodable> Encodable for Vec<T> {
fn inline_align(&self) -> usize { 8 }
fn inline_size(&self) -> usize { 16 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encode_encodable_iter(encoder, Some(self.iter_mut()))
}
}
impl<T: Decodable> Decodable for Vec<T> {
fn new_empty() -> Self {
Vec::new()
}
fn inline_align() -> usize { 8 }
fn inline_size() -> usize { 16 }
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
if decode_vec(decoder, self)? {
Ok(())
} else {
Err(Error::NotNullable)
}
}
}
impl<'a, 'b: 'a, T: Encodable> Encodable for
Option<&'a mut ExactSizeIterator<Item = T>>
{
fn inline_align(&self) -> usize { 8 }
fn inline_size(&self) -> usize { 16 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encode_encodable_iter(encoder, self.as_mut().map(|x| &mut **x))
}
}
impl<'a, T: Encodable> Encodable for Option<&'a mut [T]> {
fn inline_align(&self) -> usize { 8 }
fn inline_size(&self) -> usize { 16 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encode_encodable_iter(encoder, self.as_mut().map(|x| x.iter_mut()))
}
}
impl<T: Encodable> Encodable for Option<Vec<T>> {
fn inline_align(&self) -> usize { 8 }
fn inline_size(&self) -> usize { 16 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encode_encodable_iter(encoder, self.as_mut().map(|x| x.iter_mut()))
}
}
impl<T: Decodable> Decodable for Option<Vec<T>> {
fn new_empty() -> Self {
None
}
fn inline_align() -> usize { 8 }
fn inline_size() -> usize { 16 }
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
let was_some;
{
let vec = self.get_or_insert(Vec::new());
was_some = decode_vec(decoder, vec)?;
}
if !was_some { *self = None }
Ok(())
}
}
/// A shorthand macro for calling `Decodable::inline_size()` on a type
/// without importing the `Decodable` trait.
#[macro_export]
macro_rules! fidl_inline_size {
($type:ty) => {
<$type as $crate::encoding::Decodable>::inline_size()
}
}
/// A shorthand macro for calling `Decodable::inline_align()` on a type
/// without importing the `Decodable` trait.
#[macro_export]
macro_rules! fidl_inline_align {
($type:ty) => {
<$type as $crate::encoding::Decodable>::inline_align()
}
}
/// A shorthand macro for calling `Encodable::encode()` on a type
/// without importing the `Encodable` trait.
#[macro_export]
macro_rules! fidl_encode {
($val:expr, $encoder:expr) => {
$crate::encoding::Encodable::encode($val, $encoder)
}
}
/// A shorthand macro for calling `Decodable::decode()` on a type
/// without importing the `Decodable` trait.
#[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 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::Encodable for $name {
fn inline_align(&self) -> usize {
fidl_inline_align!($prim_ty)
}
fn inline_size(&self) -> usize {
fidl_inline_size!($prim_ty)
}
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder)
-> ::std::result::Result<(), $crate::Error>
{
fidl_encode!(&mut (*self as $prim_ty), encoder)
}
}
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 inline_align() -> usize {
fidl_inline_align!($prim_ty)
}
fn inline_size() -> usize {
fidl_inline_size!($prim_ty)
}
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder)
-> ::std::result::Result<(), $crate::Error>
{
let mut prim = fidl_new_empty!($prim_ty);
fidl_decode!(&mut prim, decoder)?;
*self = Self::from_primitive(prim).ok_or($crate::Error::Invalid)?;
Ok(())
}
}
}
}
impl Encodable for zx::Status {
fn inline_align(&self) -> usize { mem::size_of::<zx::sys::zx_status_t>() }
fn inline_size(&self) -> usize { mem::size_of::<zx::sys::zx_status_t>() }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
let slot = encoder.next_slice(mem::size_of::<zx::sys::zx_status_t>())?;
LittleEndian::write_i32(slot, self.into_raw());
Ok(())
}
}
impl Decodable for zx::Status {
fn new_empty() -> Self { Self::from_raw(0) }
fn inline_size() -> usize { mem::size_of::<zx::sys::zx_status_t>() }
fn inline_align() -> usize { mem::size_of::<zx::sys::zx_status_t>() }
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
let end = mem::size_of::<zx::sys::zx_status_t>();
let range = split_off_front(&mut decoder.buf, end)?;
*self = Self::from_raw(LittleEndian::read_i32(range));
Ok(())
}
}
impl Encodable for zx::Handle {
fn inline_align(&self) -> usize { 4 }
fn inline_size(&self) -> usize { 4 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()>
{
ALLOC_PRESENT_U32.encode(encoder)?;
let handle = take_handle(self);
encoder.handles.push(handle);
Ok(())
}
}
impl Decodable for zx::Handle {
fn new_empty() -> Self {
zx::Handle::invalid()
}
fn inline_align() -> usize { 4 }
fn inline_size() -> usize { 4 }
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 Encodable for Option<zx::Handle> {
fn inline_align(&self) -> usize { 4 }
fn inline_size(&self) -> usize { 4 }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
match self {
Some(handle) => handle.encode(encoder),
None => ALLOC_ABSENT_U32.encode(encoder),
}
}
}
impl Decodable for Option<zx::Handle> {
fn new_empty() -> Self { None }
fn inline_align() -> usize { 4 }
fn inline_size() -> usize { 4 }
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::Encodable for $ty<$($($generic,)*)*> {
fn inline_align(&self) -> usize { 4 }
fn inline_size(&self) -> usize { 4 }
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder)
-> $crate::Result<()>
{
let mut handle = $crate::encoding::take_handle(self);
fidl_encode!(&mut handle, encoder)
}
}
impl<$($($generic,)*)*> $crate::encoding::Decodable for $ty<$($($generic,)*)*> {
fn new_empty() -> Self {
<$ty<$($($generic,)*)*> as zx::HandleBased>::from_handle(zx::Handle::invalid())
}
fn inline_align() -> usize { 4 }
fn inline_size() -> usize { 4 }
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder)
-> $crate::Result<()>
{
let mut handle = zx::Handle::invalid();
fidl_decode!(&mut handle, decoder)?;
*self = <$ty<$($($generic,)*)*> as zx::HandleBased>::from_handle(handle);
Ok(())
}
}
impl<$($($generic,)*)*> $crate::encoding::Encodable for Option<$ty<$($($generic,)*)*>> {
fn inline_align(&self) -> usize { 4 }
fn inline_size(&self) -> usize { 4 }
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder)
-> $crate::Result<()>
{
match self {
Some(handle) => fidl_encode!(handle, encoder),
None => fidl_encode!(&mut $crate::encoding::ALLOC_ABSENT_U32, encoder),
}
}
}
impl<$($($generic,)*)*> $crate::encoding::Decodable for Option<$ty<$($($generic,)*)*>> {
fn new_empty() -> Self { None }
fn inline_align() -> usize { 4 }
fn inline_size() -> usize { 4 }
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder) -> $crate::Result<()> {
let mut handle: Option<zx::Handle> = None;
fidl_decode!(&mut handle, decoder)?;
*self = handle.map(Into::into);
Ok(())
}
}
)* }
}
type ZxChannel = zx::Channel;
type ZxEvent = zx::Event;
type ZxEventPair = zx::EventPair;
type ZxFifo = zx::Fifo;
type ZxGuest = zx::Guest;
type ZxInterrupt = zx::Interrupt;
type ZxJob = zx::Job;
type ZxLog = zx::Log;
type ZxProcess = zx::Process;
type ZxSocket = zx::Socket;
type ZxThread = zx::Thread;
type ZxTimer = zx::Timer;
type ZxPort = zx::Port;
type ZxVmar = zx::Vmar;
type ZxVmo = zx::Vmo;
handle_based_codable![
ZxChannel,
ZxEvent,
ZxEventPair,
ZxFifo,
ZxGuest,
ZxInterrupt,
ZxJob,
ZxLog,
ZxProcess,
ZxSocket,
ZxThread,
ZxTimer,
ZxPort,
ZxVmar,
ZxVmo,
];
/// A trait that provides automatic `Encodable` and `Decodable`
/// implementations for a container that has inline data to decode,
/// and expects to find a presence indicator at the start of its
/// encoding/decoding.
///
/// Types that implement this trait will automatically receive
/// `Encodable` and `Decodable` implementations for `Option<Self>`
/// (rather than `Option<Box<Self>>` or `Option<OutOfLine<Self>>`).
pub trait AutonullContainer {
// FIXME(cramertj) dedup size and align in this file into an
// object-safe size and align trait and a non-object-safe size and align
// trait that can be reused, with a default impl of the former for implementors
// of the latter.
/// The inline size of the object.
fn inline_align() -> usize;
/// The out-of-line size of the object.
fn inline_size() -> usize;
}
/// A trait that provides automatic `Encodable` and `Decodable`
/// implementations for `Option<Box<Self>>` and `Option<OutOfLine<Self>>`.
pub trait Autonull: Encodable + Decodable {}
/// A wrapper for FIDL types that will cause them to be encoded
/// or decoded from the out-of-line buffer rather than inline.
pub struct OutOfLine<'a, T: 'a>(pub &'a mut T);
impl<T: AutonullContainer + Encodable> Encodable for Option<T> {
fn inline_align(&self) -> usize {
<T as AutonullContainer>::inline_align()
}
fn inline_size(&self) -> usize {
<T as AutonullContainer>::inline_size()
}
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
match self {
Some(x) => x.encode(encoder),
None => {
// `None` always corresponds to a full bout of inline zeros,
// aka `ALLOC_ABSENT_u64`, with an additional zero-length for
// out-of-line vectors and tables.
for byte in encoder.next_slice(<T as AutonullContainer>::inline_size())? {
*byte = 0;
}
Ok(())
}
}
}
}
impl<T: AutonullContainer + Decodable> Decodable for Option<T> {
fn inline_align() -> usize {
<T as Decodable>::inline_align()
}
fn inline_size() -> usize {
<T as Decodable>::inline_size()
}
fn new_empty() -> Self {
None
}
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
let inline_size = <T as Decodable>::inline_size();
let mut present = false;
for byte in decoder.peek_slice(inline_size)? {
if *byte != 0 {
present = true;
break;
}
}
if present {
self.get_or_insert_with(|| T::new_empty()).decode(decoder)?;
Ok(())
} else {
*self = None;
// Eat the full `inline_size` bytes including the
// ALLOC_ABSENT that we only peeked at before
decoder.next_slice(inline_size)?;
Ok(())
}
}
}
impl<'a, T: Autonull> AutonullContainer for OutOfLine<'a, T> {
fn inline_align() -> usize {
fidl_inline_align!(u64)
}
fn inline_size() -> usize {
fidl_inline_size!(u64)
}
}
impl<'a, T: Autonull> Encodable for OutOfLine<'a, T> {
fn inline_align(&self) -> usize {
fidl_inline_align!(u64)
}
fn inline_size(&self) -> usize {
fidl_inline_size!(u64)
}
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
ALLOC_PRESENT_U64.encode(encoder)?;
encoder.write_out_of_line(
self.0.inline_size(),
|encoder| self.0.encode(encoder))
}
}
impl<T: Autonull> AutonullContainer for Box<T> {
fn inline_align() -> usize {
fidl_inline_align!(u64)
}
fn inline_size() -> usize {
fidl_inline_size!(u64)
}
}
impl<T: Autonull> Encodable for Box<T> {
fn inline_align(&self) -> usize {
fidl_inline_align!(u64)
}
fn inline_size(&self) -> usize {
fidl_inline_size!(u64)
}
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
ALLOC_PRESENT_U64.encode(encoder)?;
encoder.write_out_of_line(
(&**self).inline_size(),
|encoder| (&mut **self).encode(encoder))
}
}
impl<T: Autonull> Decodable for Box<T> {
fn inline_align() -> usize {
fidl_inline_align!(u64)
}
fn inline_size() -> usize {
fidl_inline_size!(u64)
}
fn new_empty() -> Self {
Box::new(T::new_empty())
}
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
let mut present: u64 = 0;
fidl_decode!(&mut present, decoder)?;
if present != ALLOC_PRESENT_U64 {
return Err(Error::NotNullable);
}
return decoder.read_out_of_line(
<T as Decodable>::inline_size(),
|decoder| (&mut **self).decode(decoder));
}
}
/// 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: $member_offset:expr,
},
)*],
size: $size:expr,
align: $align:expr,
) => {
impl $crate::encoding::Encodable for $name {
fn inline_align(&self) -> usize {
$align
}
fn inline_size(&self) -> usize {
$size
}
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder) -> $crate::Result<()> {
encoder.recurse(|encoder| {
let mut cur_offset = 0;
$(
// Skip to the start of the next field
encoder.next_slice($member_offset - cur_offset)?;
cur_offset = $member_offset;
fidl_encode!(&mut self.$member_name, encoder)?;
cur_offset += fidl_inline_size!($member_ty);
)*
// Skip to the end of the struct's size
encoder.next_slice($size - cur_offset)?;
Ok(())
})
}
}
impl $crate::encoding::Decodable for $name {
fn inline_align() -> usize {
$align
}
fn inline_size() -> usize {
$size
}
fn new_empty() -> Self {
Self {
$(
$member_name: fidl_new_empty!($member_ty),
)*
}
}
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder) -> $crate::Result<()> {
decoder.recurse(|decoder| {
let mut cur_offset = 0;
$(
// Skip to the start of the next field
decoder.next_slice($member_offset - cur_offset)?;
cur_offset = $member_offset;
fidl_decode!(&mut self.$member_name, decoder)?;
cur_offset += fidl_inline_size!($member_ty);
)*
// Skip to the end of the struct's size
decoder.next_slice($size - cur_offset)?;
Ok(())
})
}
}
impl $crate::encoding::Autonull for $name {}
}
}
/// Encode the provided value behind a FIDL "envelope".
pub fn encode_in_envelope<T>(val: &mut Option<&mut T>, encoder: &mut Encoder) -> Result<()>
where
T: Encodable + ?Sized
{
// u32 num_bytes
// u32 num_handles
// 64-bit presence indicator
// Record the offset of the number of bytes handles in the envelope,
// so that we can come back to it after writing the bytes and handles
// (until which point we don't know how many handles will be written).
let envelope_offset = encoder.offset;
0u32.encode(encoder)?; // num_bytes
0u32.encode(encoder)?; // num_handles
match val {
Some(x) => {
ALLOC_PRESENT_U64.encode(encoder)?;
let bytes_before = encoder.buf.len();
let handles_before = encoder.handles.len();
encoder.write_out_of_line(x.inline_size(), |e| x.encode(e))?;
let mut bytes_written = (encoder.buf.len() - bytes_before) as u32;
let mut handles_written = (encoder.handles.len() - handles_before) as u32;
// Back up and overwrite the `0s` for num_bytes and num_handles
let after_offset = encoder.offset;
encoder.offset = envelope_offset;
bytes_written.encode(encoder)?;
handles_written.encode(encoder)?;
encoder.offset = after_offset;
}
None => ALLOC_ABSENT_U64.encode(encoder)?,
}
Ok(())
}
/// A macro which implements 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 $crate::encoding::Encodable for $name {
fn inline_align(&self) -> usize { 8 }
fn inline_size(&self) -> usize { 16 }
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder) -> $crate::Result<()> {
let members = &mut [$(
($ordinal, self.$member_name.as_mut().map(|x| x as &mut $crate::encoding::Encodable)),
)*];
// Cut off the `None` elements at the tail of the table
let last_some_index = members
.iter()
.enumerate()
.rev()
.find(|(_i, val)| val.1.is_some())
.map(|(i, _val)| i);
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)?;
$crate::encoding::ALLOC_PRESENT_U64.encode(encoder)?;
let bytes_len = max_ordinal * 16; // 16 = ENVELOPE_INLINE_SIZE
encoder.write_out_of_line(bytes_len, |encoder| {
encoder.recurse(|encoder| {
let mut next_ordinal_to_write = 1;
for (ordinal, encodable) in members.iter_mut() {
let ordinal = *ordinal;
if ordinal < next_ordinal_to_write || ordinal > max_ordinal {
panic!("ordinals out of order in fidl_table! declaration");
}
while ordinal > next_ordinal_to_write {
// Fill in envelopes for missing ordinals.
$crate::encoding::encode_in_envelope::<()>(&mut None, encoder)?;
next_ordinal_to_write += 1;
}
$crate::encoding::encode_in_envelope(encodable, encoder)?;
next_ordinal_to_write += 1;
}
Ok(())
})
})
}
}
impl $crate::encoding::Decodable for $name {
fn inline_align() -> usize { 8 }
fn inline_size() -> usize { 16 }
fn new_empty() -> Self {
Self {$(
$member_name: None,
)*}
}
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder) -> $crate::Result<()> {
// Decode envelope vector header
let mut len: u64 = 0;
fidl_decode!(&mut len, decoder)?;
let mut present: u64 = 0;
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
$(
if decoder.is_empty() {
// The remaining fields have been omitted, so set them to None
self.$member_name = None;
} else {
let mut num_bytes: u32 = 0;
fidl_decode!(&mut num_bytes, decoder)?;
let mut num_handles: u32 = 0;
fidl_decode!(&mut num_handles, decoder)?;
let mut present: u64 = 0;
fidl_decode!(&mut present, decoder)?;
let bytes_before = decoder.remaining_out_of_line();
let handles_before = decoder.remaining_handles();
match present {
ALLOC_PRESENT_U64 => {
decoder.read_out_of_line(fidl_inline_size!($member_ty), |d| {
let val_ref =
self.$member_name.get_or_insert_with(
|| fidl_new_empty!($member_ty));
fidl_decode!(val_ref, d)?;
Ok(())
})?;
}
$crate::encoding::ALLOC_ABSENT_U64 => {
self.$member_name = None;
}
_ => return Err($crate::Error::Invalid),
}
if bytes_before != (decoder.remaining_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);
}
}
)*
// If there are any remaining non-empty envelopes,
// we error since the ordinal is unknown to these bindings.
//
// NOTE: this is the behavior discussed in previous FIDL
// team meetings and is consistent with the behavior on new
// extensible union variants and new interface methods.
// However, it means that receivers of tables must update
// to new generated bindings before they can receive
// messages containing new table fields.
while !decoder.is_empty() {
let mut num_bytes: u32 = 0;
fidl_decode!(&mut num_bytes, decoder)?;
let mut num_handles: u32 = 0;
fidl_decode!(&mut num_handles, decoder)?;
let mut present: u64 = 0;
fidl_decode!(&mut present, decoder)?;
if num_bytes != 0 ||
num_handles != 0 ||
present != $crate::encoding::ALLOC_ABSENT_U64
{
return Err($crate::Error::UnknownTableField);
}
}
Ok(())
})
}
}
impl $crate::encoding::AutonullContainer for $name {
fn inline_align() -> usize { 8 }
fn inline_size() -> usize { 16 }
}
}
}
/// A macro which declares a new FIDL union as a Rust enum and implements the
/// FIDL encoding and decoding traits for it.
#[macro_export]
macro_rules! fidl_union {
(
name: $name:ident,
members: [$(
$member_name:ident {
ty: $member_ty:ty,
offset: $member_offset:expr,
},
)*],
size: $size:expr,
align: $align:expr,
) => {
#[derive(Debug, PartialEq)]
pub enum $name {
$(
$member_name ( $member_ty ),
)*
}
impl $name {
fn member_index(&self) -> u32 {
#![allow(unused)]
let mut index = 0;
// TODO(cramertj): switch to `if let` when irrefutable `if let` patterns
// stabilize
$(
match *self {
$name::$member_name(_) => return index,
_ => index += 1,
}
)*
panic!("unreachable union member")
}
}
impl $crate::encoding::Encodable for $name {
fn inline_align(&self) -> usize {
$align
}
fn inline_size(&self) -> usize {
$size
}
fn encode(&mut self, encoder: &mut $crate::encoding::Encoder) -> $crate::Result<()> {
let mut member_index = self.member_index();
// Encode tag
fidl_encode!(&mut member_index, encoder)?;
encoder.recurse(|encoder| {
match self { $(
$name::$member_name ( val ) => {
// Jump to offset minus 4-byte tag
encoder.next_slice($member_offset - 4)?;
// Encode value
fidl_encode!(val, encoder)?;
// Skip to the end of the union's size
encoder.next_slice($size - (fidl_inline_size!($member_ty) + $member_offset))?;
Ok(())
}
)* }
})
}
}
impl $crate::encoding::Decodable for $name {
fn inline_align() -> usize {
$align
}
fn inline_size() -> usize {
$size
}
fn new_empty() -> Self {
#![allow(unreachable_code)]
$(
return $name::$member_name(fidl_new_empty!($member_ty));
)*
panic!("called new_empty on empty fidl union")
}
fn decode(&mut self, decoder: &mut $crate::encoding::Decoder) -> $crate::Result<()> {
#![allow(unused)]
let mut tag: u32 = 0;
fidl_decode!(&mut tag, decoder)?;
decoder.recurse(|decoder| {
let mut index = 0;
$(
if index == tag {
// Jump to offset minus 4-byte tag
decoder.next_slice($member_offset - 4)?;
// Loop will only ever run once-- if the variant is not correct,
// it is fixed up.
loop {
match self {
$name::$member_name(val) => {
fidl_decode!(val, decoder)?;
break;
}
_ => {}
}
*self = $name::$member_name(fidl_new_empty!($member_ty));
}
// Skip to the end of the union's size
decoder.next_slice($size - (fidl_inline_size!($member_ty) + $member_offset))?;
return Ok(());
}
index += 1;
)*
Err($crate::Error::UnknownUnionTag)
})
}
}
impl $crate::encoding::Autonull for $name {}
}
}
/// Header for transactional FIDL messages
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct TransactionHeader {
/// Transaction ID which identifies a request-response pair
pub tx_id: u32,
/// Flags (always zero for now)
pub flags: u32,
/// Ordinal which identifies the FIDL method
pub ordinal: u32,
}
fidl_struct! {
name: TransactionHeader,
members: [
tx_id {
ty: u32,
offset: 0,
},
flags {
ty: u32,
offset: 8, // Save 64 bits for id, even though it's only 32 bits
},
ordinal {
ty: u32,
offset: 12,
},
],
size: 16,
align: 0,
}
/// Transactional FIDL message
pub struct TransactionMessage<'a, T: 'a> {
/// Header of the message
pub header: TransactionHeader,
/// Body of the message
pub body: &'a mut T,
}
impl<'a, T: Encodable> Encodable for TransactionMessage<'a, T> {
fn inline_align(&self) -> usize { 0 }
fn inline_size(&self) -> usize {
self.header.inline_size() + self.body.inline_size()
}
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
self.header.encode(encoder)?;
(*self.body).encode(encoder)?;
Ok(())
}
}
impl<'a, T: Decodable> Decodable for TransactionMessage<'a, T> {
fn new_empty() -> Self {
panic!("cannot create an empty transaction message")
}
fn inline_align() -> usize { 0 }
fn inline_size() -> usize {
<TransactionHeader as Decodable>::inline_size() + T::inline_size()
}
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
self.header.decode(decoder)?;
(*self.body).decode(decoder)?;
Ok(())
}
}
/// Decode the transaction header from a message.
/// Returns the header and a reference to the tail of the message.
pub fn decode_transaction_header(bytes: &[u8]) -> Result<(TransactionHeader, &[u8])> {
let mut header = TransactionHeader::new_empty();
let header_len = <TransactionHeader as Decodable>::inline_size();
if bytes.len() < header_len { return Err(Error::OutOfRange); }
let (header_bytes, body_bytes) = bytes.split_at(header_len);
let handles = &mut [];
Decoder::decode_into(header_bytes, handles, &mut header)?;
Ok((header, body_bytes))
}
// Implementations of Encodable for (&mut Head, ...Tail) and Decodable for (Head, ...Tail)
macro_rules! tuple_impls {
() => {};
(($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
/*
* Invoke recursive reversal of list that ends in the macro expansion implementation
* of the reversed list
*/
tuple_impls!([($idx, $typ);] $( ($nidx => $ntyp), )*);
tuple_impls!($( ($nidx => $ntyp), )*); // invoke macro on tail
};
/*
* ([accumulatedList], listToReverse); recursively calls tuple_impls until the list to reverse
+ is empty (see next pattern)
*/
([$(($accIdx:tt, $accTyp:ident);)+]
($idx:tt => $typ:ident), $( ($nidx:tt => $ntyp:ident), )*) => {
tuple_impls!([($idx, $typ); $(($accIdx, $accTyp); )*] $( ($nidx => $ntyp), ) *);
};
// Finally expand into the implementation
([($idx:tt, $typ:ident); $( ($nidx:tt, $ntyp:ident); )*]) => {
impl<$typ, $( $ntyp ,)*>
Encodable for ($typ, $( $ntyp ,)*)
where $typ: Encodable,
$( $ntyp: Encodable,)*
{
fn inline_align(&self) -> usize {
let mut max = 0;
if max < self.$idx.inline_align() {
max = self.$idx.inline_align();
}
$(
if max < self.$nidx.inline_align() {
max = self.$nidx.inline_align();
}
)*
max
}
fn inline_size(&self) -> usize {
let mut offset = 0;
offset += self.$idx.inline_size();
$(
offset = round_up_to_align(offset, self.$nidx.inline_align());
offset += self.$nidx.inline_size();
)*
offset
}
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
encoder.recurse(|encoder| {
let mut cur_offset = 0;
self.$idx.encode(encoder)?;
cur_offset += self.$idx.inline_size();
$(
// Skip to the start of the next field
let member_offset = round_up_to_align(cur_offset, self.$nidx.inline_align());
encoder.next_slice(member_offset - cur_offset)?;
cur_offset = member_offset;
self.$nidx.encode(encoder)?;
cur_offset += self.$nidx.inline_size();
)*
// Skip to the end of the struct's size
encoder.next_slice(self.inline_size() - cur_offset)?;
Ok(())
})
}
}
impl<$typ, $( $ntyp ),*> Decodable for ($typ, $( $ntyp, )*)
where $typ: Decodable,
$( $ntyp: Decodable, )*
{
fn inline_align() -> usize {
let mut max = 0;
if max < $typ::inline_align() {
max = $typ::inline_align();
}
$(
if max < $ntyp::inline_align() {
max = $ntyp::inline_align();
}
)*
max
}
fn inline_size() -> usize {
let mut offset = 0;
offset += $typ::inline_size();
$(
offset = round_up_to_align(offset, $ntyp::inline_align());
offset += $ntyp::inline_size();
)*
offset
}
fn new_empty() -> Self {
(
$typ::new_empty(),
$(
$ntyp::new_empty(),
)*
)
}
fn decode(&mut self, decoder: &mut Decoder) -> Result<()> {
decoder.recurse(|decoder| {
let mut cur_offset = 0;
self.$idx.decode(decoder)?;
cur_offset += $typ::inline_size();
$(
// Skip to the start of the next field
let member_offset = round_up_to_align(cur_offset, $ntyp::inline_align());
decoder.next_slice(member_offset - cur_offset)?;
cur_offset = member_offset;
self.$nidx.decode(decoder)?;
cur_offset += $ntyp::inline_size();
)*
// Skip to the end of the struct's size
decoder.next_slice(Self::inline_size() - cur_offset)?;
Ok(())
})
}
}
}
}
tuple_impls!(
(10 => K),
(9 => J),
(8 => I),
(7 => H),
(6 => G),
(5 => F),
(4 => E),
(3 => D),
(2 => C),
(1 => B),
(0 => A),
);
impl Encodable for () {
fn inline_align(&self) -> usize { 0 }
fn inline_size(&self) -> usize { 0 }
fn encode(&mut self, _: &mut Encoder) -> Result<()> {
Ok(())
}
}
impl Decodable for () {
fn new_empty() -> Self { () }
fn inline_size() -> usize { 0 }
fn inline_align() -> usize { 0 }
fn decode(&mut self, _: &mut Decoder) -> Result<()> {
Ok(())
}
}
impl<'a, T> Encodable for &'a mut T where T: Encodable {
fn inline_align(&self) -> usize { (**self).inline_align() }
fn inline_size(&self) -> usize { (**self).inline_size() }
fn encode(&mut self, encoder: &mut Encoder) -> Result<()> {
(&mut **self).encode(encoder)
}
}
#[cfg(test)]
mod test {
use super::*;
use std::{fmt, u64, i64, f32, f64};
use fuchsia_zircon::AsHandleRef;
fn encode_decode<T: Encodable + Decodable>(start: &mut T) -> T {
let buf = &mut Vec::new();
let handle_buf = &mut Vec::new();
Encoder::encode(buf, handle_buf, start)
.expect("Encoding failed");
let mut out = T::new_empty();
Decoder::decode_into(buf, handle_buf, &mut out)
.expect("Decoding failed");
out
}
fn encode_assert_bytes<T: Encodable>(mut data: T, encoded_bytes: &[u8]) {
let buf = &mut Vec::new();
let handle_buf = &mut Vec::new();
Encoder::encode(buf, handle_buf, &mut data)
.expect("Encoding failed");
assert_eq!(&**buf, encoded_bytes);
}
fn assert_identity<T>(mut x: T)
where T: Encodable + Decodable + Clone + PartialEq + fmt::Debug
{
let cloned = x.clone();
assert_eq!(cloned, encode_decode(&mut x));
}
macro_rules! identities { ($($x:expr,)*) => { $(
assert_identity($x);
)* } }
#[test]
fn encode_decode_byte() {
identities![
0u8, 57u8, 255u8, 0i8, -57i8, 12i8,
];
}
#[test]
fn encode_decode_multibyte() {
identities![
0u64, 1u64, u64::MAX, u64::MIN,
0i64, 1i64, i64::MAX, i64::MIN,
0f32, 1f32, f32::MAX, f32::MIN,
0f64, 1f64, f64::MAX, f64::MIN,
];
}
#[test]
fn encode_decode_nan() {
let nan32 = encode_decode(&mut f32::NAN);
assert!(nan32.is_nan());
let nan64 = encode_decode(&mut f64::NAN);
assert!(nan64.is_nan());
}
#[test]
fn encode_decode_out_of_line() {
identities![
Vec::<i32>::new(),
vec![1, 2, 3],
None::<Vec<i32>>,
Some(Vec::<i32>::new()),
Some(vec![1, 2, 3]),
Some(vec![vec![1, 2, 3]]),
Some(vec![Some(vec![1, 2, 3])]),
"".to_string(),
"foo".to_string(),
None::<String>,
Some("".to_string()),
Some("foo".to_string()),
Some(vec![None, Some("foo".to_string())]),
vec!["foo".to_string(), "bar".to_string()],
];
}
#[test]
fn encode_handle() {
let mut handle = zx::Handle::from(zx::Port::create().expect("Port creation failed"));
let raw_handle = handle.raw_handle();
let buf = &mut Vec::new();
let handle_buf = &mut Vec::new();
Encoder::encode(buf, handle_buf, &mut handle)
.expect("Encoding failed");
assert!(handle.is_invalid());
let mut handle_out = zx::Handle::new_empty();
Decoder::decode_into(buf, handle_buf, &mut handle_out).expect("Decoding failed");
assert_eq!(raw_handle, handle_out.raw_handle());
}
#[test]
fn encode_decode_enum() {
fidl_enum!(Animal(i32) {
Dog = 0,
Cat = 1,
Frog = 2,
});
assert_eq!(Animal::from_primitive(0), Some(Animal::Dog));
assert_eq!(Animal::from_primitive(3), None);
assert_eq!(Animal::Cat.into_primitive(), 1);
identities![
Animal::Dog,
Animal::Cat,
Animal::Frog,
Animal::from_primitive(0).expect("should be dog"),
Animal::from_primitive(Animal::Cat.into_primitive()).expect("should be cat"),
];
}
#[test]
fn encode_decode_union() {
fidl_union! {
name: NumOrStr,
members: [
Num {
ty: u64,
offset: 8,
},
Str {
ty: String,
offset: 8,
},
],
size: 24,
align: 8,
};
// These need to be manually compared because of missing `PartialEq` impls.
for num in vec![0, 255, 256] {
match encode_decode(&mut NumOrStr::Num(num)) {
NumOrStr::Num(out_num) if num == out_num => {},
x => panic!("unexpected decoded value {:?}", x),
}
}
for string in vec![String::new(), "hello world!".to_string()] {
match &encode_decode(&mut NumOrStr::Str(string.clone())) {
NumOrStr::Str(out_str) if out_str == &string => {},
x => panic!("unexpected decoded value {:?}", x),
}
}
}
struct Foo {
byte: u8,
bignum: u64,
string: String,
}
fidl_struct! {
name: Foo,
members: [
byte {
ty: u8,
offset: 0,
},
bignum {
ty: u64,
offset: 8,
},
string {
ty: String,
offset: 16,
},
],
size: 32,
align: 8,
}
#[test]
fn encode_decode_struct() {
let out_foo = encode_decode(&mut Some(Box::new(Foo {
byte: 5,
bignum: 22,
string: "hello world".to_string()
}))).expect("should be some");
assert_eq!(out_foo.byte, 5);
assert_eq!(out_foo.bignum, 22);
assert_eq!(out_foo.string, "hello world");
let out_foo: Option<Box<Foo>> = encode_decode(&mut Box::new(None));
assert!(out_foo.is_none());
}
#[test]
fn encode_decode_tuple() {
let mut start: (&mut u8, &mut u64, &mut String) = (
&mut 5,
&mut 10,
&mut "foo".to_string(),
);
let mut out: (u8, u64, String) = Decodable::new_empty();
let buf = &mut Vec::new();
let handle_buf = &mut Vec::new();
Encoder::encode(buf, handle_buf, &mut start)
.expect("Encoding failed");
Decoder::decode_into(buf, handle_buf, &mut out)
.expect("Decoding failed");
assert_eq!(*start.0, out.0);
assert_eq!(*start.1, out.1);
assert_eq!(*start.2, out.2);
}
#[test]
fn encode_decode_struct_as_tuple() {
let mut start = Foo { byte: 5, bignum: 10, string: "foo".to_string() };
let mut out: (u8, u64, String) = Decodable::new_empty();
let buf = &mut Vec::new();
let handle_buf = &mut Vec::new();
Encoder::encode(buf, handle_buf, &mut start)
.expect("Encoding failed");
Decoder::decode_into(buf, handle_buf, &mut out)
.expect("Decoding failed");
assert_eq!(start.byte, out.0);
assert_eq!(start.bignum, out.1);
assert_eq!(start.string, out.2);
}
#[test]
fn encode_decode_tuple_as_struct() {
let mut start = (&mut 5u8, &mut 10u64, &mut "foo".to_string());
let mut out: Foo = Decodable::new_empty();
let buf = &mut Vec::new();
let handle_buf = &mut Vec::new();
Encoder::encode(buf, handle_buf, &mut start)
.expect("Encoding failed");
Decoder::decode_into(buf, handle_buf, &mut out)
.expect("Decoding failed");
assert_eq!(*start.0, out.byte);
assert_eq!(*start.1, out.bignum);
assert_eq!(*start.2, out.string);
}
#[test]
fn encode_decode_tuple_msg() {
let mut body_start = (&mut "foo".to_string(), &mut 5);
let mut body_out: (String, u8) = Decodable::new_empty();
let buf = &mut Vec::new();
let handle_buf = &mut Vec::new();
Encoder::encode(buf, handle_buf, &mut body_start).unwrap();
println!("buffer: {:?}", buf);
Decoder::decode_into(buf, handle_buf, &mut body_out).unwrap();
assert_eq!(body_start.0, &mut body_out.0);
assert_eq!(body_start.1, &mut body_out.1);
}
struct MyTable {
num: Option<i32>,
num_none: Option<i32>,
string: Option<String>,
handle: Option<zx::Handle>,
}
fidl_table! {
name: MyTable,
members: {
num {
ty: i32,
ordinal: 1,
},
num_none {
ty: i32,
ordinal: 2,
},
string {
ty: String,
ordinal: 3,
},
handle {
ty: zx::Handle,
ordinal: 4,
},
},
}
struct TablePrefix {
num: Option<i32>,
num_none: Option<i32>,
}
fidl_table! {
name: TablePrefix,
members: {
num {
ty: i32,
ordinal: 1,
},
num_none {
ty: i32,
ordinal: 2,
},
},
}
#[test]
fn encode_decode_table() {
// create a random handle to encode and then decode.
let handle = zx::Vmo::create(1024).expect("vmo creation failed");
let raw_handle = handle.raw_handle();
let mut starting_table = MyTable {
num: Some(5),
num_none: None,
string: Some("foo".to_string()),
handle: Some(handle.into_handle()),
};
let table_out = encode_decode(&mut starting_table);
assert_eq!(table_out.num, Some(5));
assert_eq!(table_out.num_none, None);
assert_eq!(table_out.string, Some("foo".to_string()));
assert_eq!(table_out.handle.unwrap().raw_handle(), raw_handle);
}
#[test]
fn encode_decode_table_some() {
// create a random handle to encode and then decode.
let handle = zx::Vmo::create(1024).expect("vmo creation failed");
let raw_handle = handle.raw_handle();
let mut starting_table = Some(MyTable {
num: Some(5),
num_none: None,
string: Some("foo".to_string()),
handle: Some(handle.into_handle()),
});
let table_out = encode_decode(&mut starting_table);
let table_out = table_out.expect("table was None");
assert_eq!(table_out.num, Some(5));
assert_eq!(table_out.num_none, None);
assert_eq!(table_out.string, Some("foo".to_string()));
assert_eq!(table_out.handle.unwrap().raw_handle(), raw_handle);
}
#[test]
fn encode_decode_table_none() {
let table_none = encode_decode::<Option<MyTable>>(&mut None);
assert!(table_none.is_none());
}
#[test]
fn table_encode_prefix_decode_full() {
let mut table_prefix_in = TablePrefix {
num: Some(5),
num_none: None,
};
let mut table_out: MyTable = Decodable::new_empty();
let buf = &mut Vec::new();
let handle_buf = &mut Vec::new();
Encoder::encode(buf, handle_buf, &mut table_prefix_in).unwrap();
Decoder::decode_into(buf, handle_buf, &mut table_out).unwrap();
assert_eq!(table_out.num, Some(5));
assert_eq!(table_out.num_none, None);
assert_eq!(table_out.string, None);
assert_eq!(table_out.handle, None);
}
#[test]
fn table_encode_omits_none_tail() {
// "None" fields at the tail of a table shouldn't be encoded at all.
let mut table_in = MyTable {
num: Some(5),
// These fields should all be omitted in the encoded repr,
// allowing decoding of the prefix to succeed.
num_none: None,
string: None,
handle: None,
};
let mut table_prefix_out: TablePrefix = Decodable::new_empty();
let buf = &mut Vec::new();
let handle_buf = &mut Vec::new();
Encoder::encode(buf, handle_buf, &mut table_in).unwrap();
Decoder::decode_into(buf, handle_buf, &mut table_prefix_out).unwrap();
assert_eq!(table_prefix_out.num, Some(5));
assert_eq!(table_prefix_out.num_none, None);
}
#[test]
fn table_decode_fails_on_unrecognized_tail() {
let mut table_in = MyTable {
num: Some(5),
num_none: None,
string: Some("foo".to_string()),
handle: None,
};
let mut table_prefix_out: TablePrefix = Decodable::new_empty();
let buf = &mut Vec::new();
let handle_buf = &mut Vec::new();
Encoder::encode(buf, handle_buf, &mut table_in).unwrap();
let err = Decoder::decode_into(buf, handle_buf, &mut table_prefix_out).unwrap_err();
match err {
Error::UnknownTableField => {},
err => panic!("unexpected error decoding: {:?}", err),
}
}
struct SimpleTable {
x: Option<i64>,
y: Option<i64>,
}
fidl_table! {
name: SimpleTable,
members: {
x {
ty: i64,
ordinal: 1,
},
y {
ty: i64,
ordinal: 5,
},
},
}
struct TableWithStringAndVector {
foo: Option<String>,
bar: Option<i32>,
baz: Option<Vec<u8>>,
}
fidl_table! {
name: TableWithStringAndVector,
members: {
foo {
ty: String,
ordinal: 1,
},
bar {
ty: i32,
ordinal: 2,
},
baz {
ty: Vec<u8>,
ordinal: 3,
},
},
}
#[test]
fn table_golden_simple_table_with_xy() {
let simple_table_with_xy: &[u8] = &[
5, 0, 0, 0, 0, 0, 0, 0, // max ordinal
255, 255, 255, 255, 255, 255, 255, 255, // alloc present
8, 0, 0, 0, 0, 0, 0, 0, // envelope 1: num bytes / num handles
255, 255, 255, 255, 255, 255, 255, 255, // alloc present
0, 0, 0, 0, 0, 0, 0, 0, // envelope 2: num bytes / num handles
0, 0, 0, 0, 0, 0, 0, 0, // no alloc
0, 0, 0, 0, 0, 0, 0, 0, // envelope 3: num bytes / num handles
0, 0, 0, 0, 0, 0, 0, 0, // no alloc
0, 0, 0, 0, 0, 0, 0, 0, // envelope 4: num bytes / num handles
0, 0, 0, 0, 0, 0, 0, 0, // no alloc
8, 0, 0, 0, 0, 0, 0, 0, // envelope 5: num bytes / num handles
255, 255, 255, 255, 255, 255, 255, 255, // alloc present
42, 0, 0, 0, 0, 0, 0, 0, // field X
67, 0, 0, 0, 0, 0, 0, 0, // field Y
];
encode_assert_bytes(
SimpleTable { x: Some(42), y: Some(67) },
simple_table_with_xy,
)
}
#[test]
fn table_golden_simple_table_with_y() {
let simple_table_with_y: &[u8] = &[
5, 0, 0, 0, 0, 0, 0, 0, // max ordinal
255, 255, 255, 255, 255, 255, 255, 255, // alloc present
0, 0, 0, 0, 0, 0, 0, 0, // envelope 1: num bytes / num handles
0, 0, 0, 0, 0, 0, 0, 0, // no alloc
0, 0, 0, 0, 0, 0, 0, 0, // envelope 2: num bytes / num handles
0, 0, 0, 0, 0, 0, 0, 0, // no alloc
0, 0, 0, 0, 0, 0, 0, 0, // envelope 3: num bytes / num handles
0, 0, 0, 0, 0, 0, 0, 0, // no alloc
0, 0, 0, 0, 0, 0, 0, 0, // envelope 4: num bytes / num handles
0, 0, 0, 0, 0, 0, 0, 0, // no alloc
8, 0, 0, 0, 0, 0, 0, 0, // envelope 5: num bytes / num handles
255, 255, 255, 255, 255, 255, 255, 255, // alloc present
67, 0, 0, 0, 0, 0, 0, 0, // field Y
];
encode_assert_bytes(
SimpleTable { x: None, y: Some(67) },
simple_table_with_y,
)
}
#[test]
fn table_golden_string_and_vector_hello_27() {
let table_with_string_and_vector_hello_27: &[u8] = &[
2, 0, 0, 0, 0, 0, 0, 0, // max ordinal
255, 255, 255, 255, 255, 255, 255, 255, // alloc present
24, 0, 0, 0, 0, 0, 0, 0, // envelope 1: num bytes / num handles
255, 255, 255, 255, 255, 255, 255, 255, // envelope 1: alloc present
8, 0, 0, 0, 0, 0, 0, 0, // envelope 2: num bytes / num handles
255, 255, 255, 255, 255, 255, 255, 255, // envelope 2: alloc present
5, 0, 0, 0, 0, 0, 0, 0, // element 1: length
255, 255, 255, 255, 255, 255, 255, 255, // element 1: alloc present
104, 101, 108, 108, 111, 0, 0, 0, // element 1: hello
27, 0, 0, 0, 0, 0, 0, 0, // element 2: value
];
encode_assert_bytes(
TableWithStringAndVector {
foo: Some("hello".to_string()),
bar: Some(27),
baz: None,
},
table_with_string_and_vector_hello_27,
)
}
#[test]
fn table_golden_empty_table() {
let empty_table: &[u8] = &[
0, 0, 0, 0, 0, 0, 0, 0, // max ordinal
255, 255, 255, 255, 255, 255, 255, 255, // alloc present
];
encode_assert_bytes(
SimpleTable { x: None, y: None },
empty_table,
)
}
#[test]
fn encode_decode_transaction_msg() {
let header = TransactionHeader {
tx_id: 4,
flags: 5,
ordinal: 6,
};
let body = "hello".to_string();
let start = &mut TransactionMessage { header, body: &mut body.clone() };
let (buf, handles) = (&mut vec![], &mut vec![]);
Encoder::encode(buf, handles, start).expect("Encoding failed");
let (out_header, out_buf) = decode_transaction_header(&**buf).expect("Decoding header failed");
assert_eq!(header, out_header);
let mut body_out = String::new();
Decoder::decode_into(out_buf, handles, &mut body_out).expect("Decoding body failed");
assert_eq!(body, body_out);
}
}