blob: d287ac015d7b0f670feb2268880e28fbb6688f8b [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![recursion_limit = "256"]
extern crate proc_macro;
use std::vec::Vec;
use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
use syn::{
parse_macro_input, Data, DataEnum, DataStruct, DeriveInput, Fields, Ident, Index, Member, Meta,
NestedMeta, Type,
};
/// The function that derives the recursive implementation for struct or enum.
#[proc_macro_derive(MsgOnSocket, attributes(msg_on_socket))]
pub fn msg_on_socket_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let impl_for_input = socket_msg_impl(input);
impl_for_input.into()
}
fn socket_msg_impl(input: DeriveInput) -> TokenStream {
if !input.generics.params.is_empty() {
return quote! {
compile_error!("derive(SocketMsg) does not support generic parameters");
};
}
match input.data {
Data::Struct(ds) => {
if is_named_struct(&ds) {
impl_for_named_struct(input.ident, ds)
} else {
impl_for_tuple_struct(input.ident, ds)
}
}
Data::Enum(de) => impl_for_enum(input.ident, de),
_ => quote! {
compile_error!("derive(SocketMsg) only support struct and enum");
},
}
}
fn is_named_struct(ds: &DataStruct) -> bool {
match &ds.fields {
Fields::Named(_f) => true,
_ => false,
}
}
/************************** Named Struct Impls ********************************************/
struct StructField {
member: Member,
ty: Type,
skipped: bool,
}
fn impl_for_named_struct(name: Ident, ds: DataStruct) -> TokenStream {
let fields = get_struct_fields(ds);
let uses_fd_impl = define_uses_fd_for_struct(&fields);
let buffer_sizes_impls = define_buffer_size_for_struct(&fields);
let read_buffer = define_read_buffer_for_struct(&name, &fields);
let write_buffer = define_write_buffer_for_struct(&name, &fields);
quote! {
impl msg_socket::MsgOnSocket for #name {
#uses_fd_impl
#buffer_sizes_impls
#read_buffer
#write_buffer
}
}
}
// Flatten struct fields.
fn get_struct_fields(ds: DataStruct) -> Vec<StructField> {
let fields = match ds.fields {
Fields::Named(fields_named) => fields_named.named,
_ => {
panic!("Struct must have named fields");
}
};
let mut vec = Vec::new();
for field in fields {
let member = match field.ident {
Some(ident) => Member::Named(ident),
None => panic!("Unknown Error."),
};
let ty = field.ty;
let mut skipped = false;
for attr in field
.attrs
.iter()
.filter(|attr| attr.path.is_ident("msg_on_socket"))
{
match attr.parse_meta().unwrap() {
Meta::List(meta) => {
for nested in meta.nested {
match nested {
NestedMeta::Meta(Meta::Path(ref meta_path))
if meta_path.is_ident("skip") =>
{
skipped = true;
}
_ => panic!("unrecognized attribute meta `{}`", quote! { #nested }),
}
}
}
_ => panic!("unrecognized attribute `{}`", quote! { #attr }),
}
}
vec.push(StructField {
member,
ty,
skipped,
});
}
vec
}
fn define_uses_fd_for_struct(fields: &[StructField]) -> TokenStream {
let field_types: Vec<_> = fields
.iter()
.filter(|f| !f.skipped)
.map(|f| &f.ty)
.collect();
if field_types.is_empty() {
return quote!();
}
quote! {
fn uses_fd() -> bool {
#(<#field_types>::uses_fd())||*
}
}
}
fn define_buffer_size_for_struct(fields: &[StructField]) -> TokenStream {
let (msg_size, fd_count) = get_fields_buffer_size_sum(fields);
quote! {
fn msg_size(&self) -> usize {
#msg_size
}
fn fd_count(&self) -> usize {
#fd_count
}
}
}
fn define_read_buffer_for_struct(_name: &Ident, fields: &[StructField]) -> TokenStream {
let mut read_fields = Vec::new();
let mut init_fields = Vec::new();
for field in fields {
let ident = match &field.member {
Member::Named(ident) => ident,
Member::Unnamed(_) => unreachable!(),
};
let name = ident.clone();
if field.skipped {
let ty = &field.ty;
init_fields.push(quote! {
#name: <#ty>::default()
});
continue;
}
let read_field = read_from_buffer_and_move_offset(&ident, &field.ty);
read_fields.push(read_field);
init_fields.push(quote!(#name));
}
quote! {
unsafe fn read_from_buffer(
buffer: &[u8],
fds: &[std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<(Self, usize)> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
#(#read_fields)*
Ok((
Self {
#(#init_fields),*
},
__fd_offset
))
}
}
}
fn define_write_buffer_for_struct(_name: &Ident, fields: &[StructField]) -> TokenStream {
let mut write_fields = Vec::new();
for field in fields {
if field.skipped {
continue;
}
let ident = match &field.member {
Member::Named(ident) => ident,
Member::Unnamed(_) => unreachable!(),
};
let write_field = write_to_buffer_and_move_offset(&ident);
write_fields.push(write_field);
}
quote! {
fn write_to_buffer(
&self,
buffer: &mut [u8],
fds: &mut [std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<usize> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
#(#write_fields)*
Ok(__fd_offset)
}
}
}
/************************** Enum Impls ********************************************/
fn impl_for_enum(name: Ident, de: DataEnum) -> TokenStream {
let uses_fd_impl = define_uses_fd_for_enum(&de);
let buffer_sizes_impls = define_buffer_size_for_enum(&name, &de);
let read_buffer = define_read_buffer_for_enum(&name, &de);
let write_buffer = define_write_buffer_for_enum(&name, &de);
quote! {
impl msg_socket::MsgOnSocket for #name {
#uses_fd_impl
#buffer_sizes_impls
#read_buffer
#write_buffer
}
}
}
fn define_uses_fd_for_enum(de: &DataEnum) -> TokenStream {
let mut variant_field_types = Vec::new();
for variant in &de.variants {
for variant_field_ty in variant.fields.iter().map(|f| &f.ty) {
variant_field_types.push(variant_field_ty);
}
}
if variant_field_types.len() == 0 {
return quote!();
}
quote! {
fn uses_fd() -> bool {
#(<#variant_field_types>::uses_fd())||*
}
}
}
fn define_buffer_size_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
let mut msg_size_match_variants = Vec::new();
let mut fd_count_match_variants = Vec::new();
for variant in &de.variants {
let variant_name = &variant.ident;
match &variant.fields {
Fields::Named(fields) => {
let mut tmp_names = Vec::new();
for field in &fields.named {
tmp_names.push(field.ident.clone().unwrap());
}
let v = quote! {
#name::#variant_name { #(#tmp_names),* } => #(#tmp_names.msg_size())+*,
};
msg_size_match_variants.push(v);
let v = quote! {
#name::#variant_name { #(#tmp_names),* } => #(#tmp_names.fd_count())+*,
};
fd_count_match_variants.push(v);
}
Fields::Unnamed(fields) => {
let mut tmp_names = Vec::new();
for idx in 0..fields.unnamed.len() {
let tmp_name = format!("enum_field{}", idx);
let tmp_name = Ident::new(&tmp_name, Span::call_site());
tmp_names.push(tmp_name.clone());
}
let v = quote! {
#name::#variant_name(#(#tmp_names),*) => #(#tmp_names.msg_size())+*,
};
msg_size_match_variants.push(v);
let v = quote! {
#name::#variant_name(#(#tmp_names),*) => #(#tmp_names.fd_count())+*,
};
fd_count_match_variants.push(v);
}
Fields::Unit => {
let v = quote! {
#name::#variant_name => 0,
};
msg_size_match_variants.push(v.clone());
fd_count_match_variants.push(v);
}
}
}
quote! {
fn msg_size(&self) -> usize {
1 + match self {
#(#msg_size_match_variants)*
}
}
fn fd_count(&self) -> usize {
match self {
#(#fd_count_match_variants)*
}
}
}
}
fn define_read_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
let mut match_variants = Vec::new();
let de = de.clone();
for (idx, variant) in de.variants.iter().enumerate() {
let idx = idx as u8;
let variant_name = &variant.ident;
match &variant.fields {
Fields::Named(fields) => {
let mut tmp_names = Vec::new();
let mut read_tmps = Vec::new();
for f in &fields.named {
tmp_names.push(f.ident.clone());
let read_tmp =
read_from_buffer_and_move_offset(f.ident.as_ref().unwrap(), &f.ty);
read_tmps.push(read_tmp);
}
let v = quote! {
#idx => {
let mut __offset = 1usize;
let mut __fd_offset = 0usize;
#(#read_tmps)*
Ok((#name::#variant_name { #(#tmp_names),* }, __fd_offset))
}
};
match_variants.push(v);
}
Fields::Unnamed(fields) => {
let mut tmp_names = Vec::new();
let mut read_tmps = Vec::new();
for (idx, field) in fields.unnamed.iter().enumerate() {
let tmp_name = format_ident!("enum_field{}", idx);
tmp_names.push(tmp_name.clone());
let read_tmp = read_from_buffer_and_move_offset(&tmp_name, &field.ty);
read_tmps.push(read_tmp);
}
let v = quote! {
#idx => {
let mut __offset = 1usize;
let mut __fd_offset = 0usize;
#(#read_tmps)*
Ok((#name::#variant_name( #(#tmp_names),*), __fd_offset))
}
};
match_variants.push(v);
}
Fields::Unit => {
let v = quote! {
#idx => Ok((#name::#variant_name, 0)),
};
match_variants.push(v);
}
}
}
quote! {
unsafe fn read_from_buffer(
buffer: &[u8],
fds: &[std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<(Self, usize)> {
let v = buffer.get(0).ok_or(msg_socket::MsgError::WrongMsgBufferSize)?;
match v {
#(#match_variants)*
_ => Err(msg_socket::MsgError::InvalidType),
}
}
}
}
fn define_write_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
let mut match_variants = Vec::new();
let de = de.clone();
for (idx, variant) in de.variants.iter().enumerate() {
let idx = idx as u8;
let variant_name = &variant.ident;
match &variant.fields {
Fields::Named(fields) => {
let mut tmp_names = Vec::new();
let mut write_tmps = Vec::new();
for f in &fields.named {
tmp_names.push(f.ident.clone().unwrap());
let write_tmp =
enum_write_to_buffer_and_move_offset(&f.ident.as_ref().unwrap());
write_tmps.push(write_tmp);
}
let v = quote! {
#name::#variant_name { #(#tmp_names),* } => {
buffer[0] = #idx;
let mut __offset = 1usize;
let mut __fd_offset = 0usize;
#(#write_tmps)*
Ok(__fd_offset)
}
};
match_variants.push(v);
}
Fields::Unnamed(fields) => {
let mut tmp_names = Vec::new();
let mut write_tmps = Vec::new();
for idx in 0..fields.unnamed.len() {
let tmp_name = format_ident!("enum_field{}", idx);
tmp_names.push(tmp_name.clone());
let write_tmp = enum_write_to_buffer_and_move_offset(&tmp_name);
write_tmps.push(write_tmp);
}
let v = quote! {
#name::#variant_name(#(#tmp_names),*) => {
buffer[0] = #idx;
let mut __offset = 1usize;
let mut __fd_offset = 0usize;
#(#write_tmps)*
Ok(__fd_offset)
}
};
match_variants.push(v);
}
Fields::Unit => {
let v = quote! {
#name::#variant_name => {
buffer[0] = #idx;
Ok(0)
}
};
match_variants.push(v);
}
}
}
quote! {
fn write_to_buffer(
&self,
buffer: &mut [u8],
fds: &mut [std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<usize> {
if buffer.is_empty() {
return Err(msg_socket::MsgError::WrongMsgBufferSize)
}
match self {
#(#match_variants)*
}
}
}
}
fn enum_write_to_buffer_and_move_offset(name: &Ident) -> TokenStream {
quote! {
let o = #name.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
__offset += #name.msg_size();
__fd_offset += o;
}
}
/************************** Tuple Impls ********************************************/
fn impl_for_tuple_struct(name: Ident, ds: DataStruct) -> TokenStream {
let fields = get_tuple_fields(ds);
let uses_fd_impl = define_uses_fd_for_tuples(&fields);
let buffer_sizes_impls = define_buffer_size_for_struct(&fields);
let read_buffer = define_read_buffer_for_tuples(&name, &fields);
let write_buffer = define_write_buffer_for_tuples(&name, &fields);
quote! {
impl msg_socket::MsgOnSocket for #name {
#uses_fd_impl
#buffer_sizes_impls
#read_buffer
#write_buffer
}
}
}
fn get_tuple_fields(ds: DataStruct) -> Vec<StructField> {
let mut field_idents = Vec::new();
let fields = match ds.fields {
Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed,
_ => {
panic!("Tuple struct must have unnamed fields.");
}
};
for (idx, field) in fields.iter().enumerate() {
let member = Member::Unnamed(Index::from(idx));
let ty = field.ty.clone();
field_idents.push(StructField {
member,
ty,
skipped: false,
});
}
field_idents
}
fn define_uses_fd_for_tuples(fields: &[StructField]) -> TokenStream {
if fields.len() == 0 {
return quote!();
}
let field_types = fields.iter().map(|f| &f.ty);
quote! {
fn uses_fd() -> bool {
#(<#field_types>::uses_fd())||*
}
}
}
fn define_read_buffer_for_tuples(name: &Ident, fields: &[StructField]) -> TokenStream {
let mut read_fields = Vec::new();
let mut init_fields = Vec::new();
for (idx, field) in fields.iter().enumerate() {
let tmp_name = format!("tuple_tmp{}", idx);
let tmp_name = Ident::new(&tmp_name, Span::call_site());
let read_field = read_from_buffer_and_move_offset(&tmp_name, &field.ty);
read_fields.push(read_field);
init_fields.push(quote!(#tmp_name));
}
quote! {
unsafe fn read_from_buffer(
buffer: &[u8],
fds: &[std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<(Self, usize)> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
#(#read_fields)*
Ok((
#name (
#(#init_fields),*
),
__fd_offset
))
}
}
}
fn define_write_buffer_for_tuples(name: &Ident, fields: &[StructField]) -> TokenStream {
let mut write_fields = Vec::new();
let mut tmp_names = Vec::new();
for idx in 0..fields.len() {
let tmp_name = format_ident!("tuple_tmp{}", idx);
let write_field = enum_write_to_buffer_and_move_offset(&tmp_name);
write_fields.push(write_field);
tmp_names.push(tmp_name);
}
quote! {
fn write_to_buffer(
&self,
buffer: &mut [u8],
fds: &mut [std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<usize> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
let #name( #(#tmp_names),* ) = self;
#(#write_fields)*
Ok(__fd_offset)
}
}
}
/************************** Helpers ********************************************/
fn get_fields_buffer_size_sum(fields: &[StructField]) -> (TokenStream, TokenStream) {
let fields: Vec<_> = fields
.iter()
.filter(|f| !f.skipped)
.map(|f| &f.member)
.collect();
if fields.len() > 0 {
(
quote! {
#( self.#fields.msg_size() as usize )+*
},
quote! {
#( self.#fields.fd_count() as usize )+*
},
)
} else {
(quote!(0), quote!(0))
}
}
fn read_from_buffer_and_move_offset(name: &Ident, ty: &Type) -> TokenStream {
quote! {
let t = <#ty>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let #name = t.0;
}
}
fn write_to_buffer_and_move_offset(name: &Ident) -> TokenStream {
quote! {
let o = self.#name.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
__offset += self.#name.msg_size();
__fd_offset += o;
}
}
#[cfg(test)]
mod tests {
use crate::socket_msg_impl;
use quote::quote;
use syn::{parse_quote, DeriveInput};
#[test]
fn end_to_end_struct_test() {
let input: DeriveInput = parse_quote! {
struct MyMsg {
a: u8,
b: RawFd,
c: u32,
}
};
let expected = quote! {
impl msg_socket::MsgOnSocket for MyMsg {
fn uses_fd() -> bool {
<u8>::uses_fd() || <RawFd>::uses_fd() || <u32>::uses_fd()
}
fn msg_size(&self) -> usize {
self.a.msg_size() as usize
+ self.b.msg_size() as usize
+ self.c.msg_size() as usize
}
fn fd_count(&self) -> usize {
self.a.fd_count() as usize
+ self.b.fd_count() as usize
+ self.c.fd_count() as usize
}
unsafe fn read_from_buffer(
buffer: &[u8],
fds: &[std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<(Self, usize)> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
let t = <u8>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let a = t.0;
let t = <RawFd>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let b = t.0;
let t = <u32>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let c = t.0;
Ok((Self { a, b, c }, __fd_offset))
}
fn write_to_buffer(
&self,
buffer: &mut [u8],
fds: &mut [std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<usize> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
let o = self
.a
.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
__offset += self.a.msg_size();
__fd_offset += o;
let o = self
.b
.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
__offset += self.b.msg_size();
__fd_offset += o;
let o = self
.c
.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
__offset += self.c.msg_size();
__fd_offset += o;
Ok(__fd_offset)
}
}
};
assert_eq!(socket_msg_impl(input).to_string(), expected.to_string());
}
#[test]
fn end_to_end_tuple_struct_test() {
let input: DeriveInput = parse_quote! {
struct MyMsg(u8, u32, File);
};
let expected = quote! {
impl msg_socket::MsgOnSocket for MyMsg {
fn uses_fd() -> bool {
<u8>::uses_fd() || <u32>::uses_fd() || <File>::uses_fd()
}
fn msg_size(&self) -> usize {
self.0.msg_size() as usize
+ self.1.msg_size() as usize + self.2.msg_size() as usize
}
fn fd_count(&self) -> usize {
self.0.fd_count() as usize
+ self.1.fd_count() as usize
+ self.2.fd_count() as usize
}
unsafe fn read_from_buffer(
buffer: &[u8],
fds: &[std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<(Self, usize)> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
let t = <u8>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let tuple_tmp0 = t.0;
let t = <u32>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let tuple_tmp1 = t.0;
let t = <File>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let tuple_tmp2 = t.0;
Ok((MyMsg(tuple_tmp0, tuple_tmp1, tuple_tmp2), __fd_offset))
}
fn write_to_buffer(
&self,
buffer: &mut [u8],
fds: &mut [std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<usize> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
let MyMsg(tuple_tmp0, tuple_tmp1, tuple_tmp2) = self;
let o = tuple_tmp0.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
__offset += tuple_tmp0.msg_size();
__fd_offset += o;
let o = tuple_tmp1.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
__offset += tuple_tmp1.msg_size();
__fd_offset += o;
let o = tuple_tmp2.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
__offset += tuple_tmp2.msg_size();
__fd_offset += o;
Ok(__fd_offset)
}
}
};
assert_eq!(socket_msg_impl(input).to_string(), expected.to_string());
}
#[test]
fn end_to_end_enum_test() {
let input: DeriveInput = parse_quote! {
enum MyMsg {
A(u8),
B,
C {
f0: u8,
f1: RawFd,
},
}
};
let expected = quote! {
impl msg_socket::MsgOnSocket for MyMsg {
fn uses_fd() -> bool {
<u8>::uses_fd() || <u8>::uses_fd() || <RawFd>::uses_fd()
}
fn msg_size(&self) -> usize {
1 + match self {
MyMsg::A(enum_field0) => enum_field0.msg_size(),
MyMsg::B => 0,
MyMsg::C { f0, f1 } => f0.msg_size() + f1.msg_size(),
}
}
fn fd_count(&self) -> usize {
match self {
MyMsg::A(enum_field0) => enum_field0.fd_count(),
MyMsg::B => 0,
MyMsg::C { f0, f1 } => f0.fd_count() + f1.fd_count(),
}
}
unsafe fn read_from_buffer(
buffer: &[u8],
fds: &[std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<(Self, usize)> {
let v = buffer
.get(0)
.ok_or(msg_socket::MsgError::WrongMsgBufferSize)?;
match v {
0u8 => {
let mut __offset = 1usize;
let mut __fd_offset = 0usize;
let t = <u8>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let enum_field0 = t.0;
Ok((MyMsg::A(enum_field0), __fd_offset))
}
1u8 => Ok((MyMsg::B, 0)),
2u8 => {
let mut __offset = 1usize;
let mut __fd_offset = 0usize;
let t = <u8>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let f0 = t.0;
let t = <RawFd>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
__offset += t.0.msg_size();
__fd_offset += t.1;
let f1 = t.0;
Ok((MyMsg::C { f0, f1 }, __fd_offset))
}
_ => Err(msg_socket::MsgError::InvalidType),
}
}
fn write_to_buffer(
&self,
buffer: &mut [u8],
fds: &mut [std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<usize> {
if buffer.is_empty() {
return Err(msg_socket::MsgError::WrongMsgBufferSize)
}
match self {
MyMsg::A(enum_field0) => {
buffer[0] = 0u8;
let mut __offset = 1usize;
let mut __fd_offset = 0usize;
let o = enum_field0
.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
__offset += enum_field0.msg_size();
__fd_offset += o;
Ok(__fd_offset)
}
MyMsg::B => {
buffer[0] = 1u8;
Ok(0)
}
MyMsg::C { f0, f1 } => {
buffer[0] = 2u8;
let mut __offset = 1usize;
let mut __fd_offset = 0usize;
let o = f0.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
__offset += f0.msg_size();
__fd_offset += o;
let o = f1.write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
__offset += f1.msg_size();
__fd_offset += o;
Ok(__fd_offset)
}
}
}
}
};
assert_eq!(socket_msg_impl(input).to_string(), expected.to_string());
}
#[test]
fn end_to_end_struct_skip_test() {
let input: DeriveInput = parse_quote! {
struct MyMsg {
#[msg_on_socket(skip)]
a: u8,
}
};
let expected = quote! {
impl msg_socket::MsgOnSocket for MyMsg {
fn msg_size(&self) -> usize {
0
}
fn fd_count(&self) -> usize {
0
}
unsafe fn read_from_buffer(
buffer: &[u8],
fds: &[std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<(Self, usize)> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
Ok((Self { a: <u8>::default() }, __fd_offset))
}
fn write_to_buffer(
&self,
buffer: &mut [u8],
fds: &mut [std::os::unix::io::RawFd],
) -> msg_socket::MsgResult<usize> {
let mut __offset = 0usize;
let mut __fd_offset = 0usize;
Ok(__fd_offset)
}
}
};
assert_eq!(socket_msg_impl(input).to_string(), expected.to_string());
}
}