summary refs log tree commit diff
path: root/msg_socket
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2020-04-10 13:44:58 +0000
committerAlyssa Ross <hi@alyssa.is>2020-04-10 13:45:14 +0000
commit8404e234c3428a682dfd5ee900936a8032243ba7 (patch)
tree458d0c9db4e145c1ace3ea7e50c3a50a45f020c3 /msg_socket
parentd1ea7fc8d6b750ba75df719fb932984ab1ef5f11 (diff)
parent4ee9bffbd5722ac6602abaac6f691917add12f48 (diff)
downloadcrosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar
crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar.gz
crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar.bz2
crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar.lz
crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar.xz
crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.tar.zst
crosvm-8404e234c3428a682dfd5ee900936a8032243ba7.zip
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'msg_socket')
-rw-r--r--msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs471
-rw-r--r--msg_socket/src/lib.rs25
-rw-r--r--msg_socket/src/msg_on_socket.rs232
3 files changed, 446 insertions, 282 deletions
diff --git a/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs b/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs
index a7988c6..fe6cb29 100644
--- a/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs
+++ b/msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs
@@ -8,8 +8,10 @@ extern crate proc_macro;
 use std::vec::Vec;
 
 use proc_macro2::{Span, TokenStream};
-use quote::quote;
-use syn::{parse_macro_input, Data, DataEnum, DataStruct, DeriveInput, Fields, Ident};
+use quote::{format_ident, quote};
+use syn::{
+    parse_macro_input, Data, DataEnum, DataStruct, DeriveInput, Fields, Ident, Index, Member, Type,
+};
 
 /// The function that derives the recursive implementation for struct or enum.
 #[proc_macro_derive(MsgOnSocket)]
@@ -50,13 +52,14 @@ fn is_named_struct(ds: &DataStruct) -> bool {
 /************************** Named Struct Impls ********************************************/
 fn impl_for_named_struct(name: Ident, ds: DataStruct) -> TokenStream {
     let fields = get_struct_fields(ds);
-    let fields_types = get_types_from_fields_vec(&fields);
-    let buffer_sizes_impls = define_buffer_size_for_struct(&fields_types);
+    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
@@ -64,17 +67,8 @@ fn impl_for_named_struct(name: Ident, ds: DataStruct) -> TokenStream {
     }
 }
 
-fn get_types_from_fields_vec(v: &[(Ident, syn::Type)]) -> Vec<syn::Type> {
-    let mut fields_types = Vec::new();
-    for (_i, t) in v {
-        fields_types.push(t.clone());
-    }
-    fields_types
-}
-
 // Flatten struct fields.
-// "myfield : Type" -> \(ident\("myfield"\), Token\(Type\)\)
-fn get_struct_fields(ds: DataStruct) -> Vec<(Ident, syn::Type)> {
+fn get_struct_fields(ds: DataStruct) -> Vec<(Member, Type)> {
     let fields = match ds.fields {
         Fields::Named(fields_named) => fields_named.named,
         _ => {
@@ -83,35 +77,52 @@ fn get_struct_fields(ds: DataStruct) -> Vec<(Ident, syn::Type)> {
     };
     let mut vec = Vec::new();
     for field in fields {
-        let ident = match field.ident {
-            Some(ident) => ident,
+        let member = match field.ident {
+            Some(ident) => Member::Named(ident),
             None => panic!("Unknown Error."),
         };
         let ty = field.ty;
-        vec.push((ident, ty));
+        vec.push((member, ty));
     }
     vec
 }
 
-fn define_buffer_size_for_struct(field_types: &[syn::Type]) -> TokenStream {
-    let (msg_size, max_fd_count) = get_fields_buffer_size_sum(field_types);
+fn define_uses_fd_for_struct(fields: &[(Member, Type)]) -> TokenStream {
+    if fields.len() == 0 {
+        return quote!();
+    }
+
+    let field_types = fields.iter().map(|(_, ty)| ty);
+    quote! {
+        fn uses_fd() -> bool {
+            #(<#field_types>::uses_fd())||*
+        }
+    }
+}
+
+fn define_buffer_size_for_struct(fields: &[(Member, Type)]) -> TokenStream {
+    let (msg_size, fd_count) = get_fields_buffer_size_sum(fields);
     quote! {
-        fn msg_size() -> usize {
+        fn msg_size(&self) -> usize {
             #msg_size
         }
-        fn max_fd_count() -> usize {
-            #max_fd_count
+        fn fd_count(&self) -> usize {
+            #fd_count
         }
     }
 }
 
-fn define_read_buffer_for_struct(_name: &Ident, fields: &[(Ident, syn::Type)]) -> TokenStream {
+fn define_read_buffer_for_struct(_name: &Ident, fields: &[(Member, Type)]) -> TokenStream {
     let mut read_fields = Vec::new();
     let mut init_fields = Vec::new();
-    for f in fields {
-        let read_field = read_from_buffer_and_move_offset(&f.0, &f.1);
+    for (field_member, field_ty) in fields {
+        let ident = match field_member {
+            Member::Named(ident) => ident,
+            Member::Unnamed(_) => unreachable!(),
+        };
+        let read_field = read_from_buffer_and_move_offset(&ident, &field_ty);
         read_fields.push(read_field);
-        let name = f.0.clone();
+        let name = ident.clone();
         init_fields.push(quote!(#name));
     }
     quote! {
@@ -132,10 +143,14 @@ fn define_read_buffer_for_struct(_name: &Ident, fields: &[(Ident, syn::Type)]) -
     }
 }
 
-fn define_write_buffer_for_struct(_name: &Ident, fields: &[(Ident, syn::Type)]) -> TokenStream {
+fn define_write_buffer_for_struct(_name: &Ident, fields: &[(Member, Type)]) -> TokenStream {
     let mut write_fields = Vec::new();
-    for f in fields {
-        let write_field = write_to_buffer_and_move_offset(&f.0, &f.1);
+    for (field_member, _) in fields {
+        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! {
@@ -154,13 +169,13 @@ fn define_write_buffer_for_struct(_name: &Ident, fields: &[(Ident, syn::Type)])
 
 /************************** Enum Impls ********************************************/
 fn impl_for_enum(name: Ident, de: DataEnum) -> TokenStream {
-    let variants = get_enum_variant_types(&de);
-    let buffer_sizes_impls = define_buffer_size_for_enum(&variants);
-
+    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
@@ -168,74 +183,103 @@ fn impl_for_enum(name: Ident, de: DataEnum) -> TokenStream {
     }
 }
 
-fn define_buffer_size_for_enum(variants: &[(Ident, Vec<syn::Type>)]) -> TokenStream {
-    let mut variant_buffer_sizes = Vec::new();
-    let mut variant_fd_sizes = Vec::new();
-    for v in variants {
-        let (msg_size_impl, fd_count_impl) = get_fields_buffer_size_sum(&v.1);
-        variant_buffer_sizes.push(msg_size_impl);
-        variant_fd_sizes.push(fd_count_impl);
+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);
+        }
     }
     quote! {
-        fn msg_size() -> usize {
-            // First byte is used for variant.
-            [#(#variant_buffer_sizes,)*].iter().max().unwrap().clone() as usize + 1
-        }
-        fn max_fd_count() -> usize {
-            [#(#variant_fd_sizes,)*].iter().max().unwrap().clone() as usize
+        fn uses_fd() -> bool {
+            #(<#variant_field_types>::uses_fd())||*
         }
     }
 }
 
-// Flatten enum variants. Return value = \[variant_name, \[types_of_this_variant\]\]
-fn get_enum_variant_types(de: &DataEnum) -> Vec<(Ident, Vec<syn::Type>)> {
-    let mut variants = Vec::new();
-    let de = de.clone();
-    for v in de.variants {
-        let name = v.ident;
-        match v.fields {
+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 vec = Vec::new();
-                for field in fields.unnamed {
-                    let ty = field.ty;
-                    vec.push(ty);
+                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());
                 }
-                variants.push((name, vec));
+
+                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 => {
-                variants.push((name, Vec::new()));
-                continue;
+                let v = quote! {
+                    #name::#variant_name => 0,
+                };
+                msg_size_match_variants.push(v.clone());
+                fd_count_match_variants.push(v);
             }
-            Fields::Named(fields) => {
-                let mut vec = Vec::new();
-                for field in fields.named {
-                    let ty = field.ty;
-                    vec.push(ty);
-                }
-                variants.push((name, vec));
+        }
+    }
+
+    quote! {
+        fn msg_size(&self) -> usize {
+            1 + match self {
+                #(#msg_size_match_variants)*
             }
-        };
+        }
+        fn fd_count(&self) -> usize {
+            match self {
+                #(#fd_count_match_variants)*
+            }
+        }
     }
-    variants
 }
 
 fn define_read_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
     let mut match_variants = Vec::new();
     let de = de.clone();
-    let mut i = 0u8;
-    for v in de.variants {
-        let variant_name = v.ident;
-        match v.fields {
+    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 {
+                for f in &fields.named {
                     tmp_names.push(f.ident.clone());
-                    let read_tmp = read_from_buffer_and_move_offset(&f.ident.unwrap(), &f.ty);
+                    let read_tmp =
+                        read_from_buffer_and_move_offset(f.ident.as_ref().unwrap(), &f.ty);
                     read_tmps.push(read_tmp);
                 }
                 let v = quote! {
-                    #i => {
+                    #idx => {
                         let mut __offset = 1usize;
                         let mut __fd_offset = 0usize;
                         #(#read_tmps)*
@@ -247,18 +291,15 @@ fn define_read_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
             Fields::Unnamed(fields) => {
                 let mut tmp_names = Vec::new();
                 let mut read_tmps = Vec::new();
-                let mut j = 0usize;
-                for f in fields.unnamed {
-                    let tmp_name = format!("enum_variant_tmp{}", j);
-                    let tmp_name = Ident::new(&tmp_name, Span::call_site());
+                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, &f.ty);
+                    let read_tmp = read_from_buffer_and_move_offset(&tmp_name, &field.ty);
                     read_tmps.push(read_tmp);
-                    j += 1;
                 }
 
                 let v = quote! {
-                    #i => {
+                    #idx => {
                         let mut __offset = 1usize;
                         let mut __fd_offset = 0usize;
                         #(#read_tmps)*
@@ -269,19 +310,18 @@ fn define_read_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
             }
             Fields::Unit => {
                 let v = quote! {
-                    #i => Ok((#name::#variant_name, 0)),
+                    #idx => Ok((#name::#variant_name, 0)),
                 };
                 match_variants.push(v);
             }
         }
-        i += 1;
     }
     quote! {
         unsafe fn read_from_buffer(
             buffer: &[u8],
             fds: &[std::os::unix::io::RawFd],
         ) -> msg_socket::MsgResult<(Self, usize)> {
-            let v = buffer[0];
+            let v = buffer.get(0).ok_or(msg_socket::MsgError::WrongMsgBufferSize)?;
             match v {
                 #(#match_variants)*
                 _ => Err(msg_socket::MsgError::InvalidType),
@@ -292,23 +332,24 @@ fn define_read_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
 
 fn define_write_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
     let mut match_variants = Vec::new();
-    let mut i = 0u8;
     let de = de.clone();
-    for v in de.variants {
-        let variant_name = v.ident;
-        match v.fields {
+    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 {
+                for f in &fields.named {
                     tmp_names.push(f.ident.clone().unwrap());
-                    let write_tmp = enum_write_to_buffer_and_move_offset(&f.ident.unwrap(), &f.ty);
+                    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] = #i;
+                        buffer[0] = #idx;
                         let mut __offset = 1usize;
                         let mut __fd_offset = 0usize;
                         #(#write_tmps)*
@@ -320,19 +361,16 @@ fn define_write_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
             Fields::Unnamed(fields) => {
                 let mut tmp_names = Vec::new();
                 let mut write_tmps = Vec::new();
-                let mut j = 0usize;
-                for f in fields.unnamed {
-                    let tmp_name = format!("enum_variant_tmp{}", j);
-                    let tmp_name = Ident::new(&tmp_name, Span::call_site());
+                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, &f.ty);
+                    let write_tmp = enum_write_to_buffer_and_move_offset(&tmp_name);
                     write_tmps.push(write_tmp);
-                    j += 1;
                 }
 
                 let v = quote! {
                     #name::#variant_name(#(#tmp_names),*) => {
-                        buffer[0] = #i;
+                        buffer[0] = #idx;
                         let mut __offset = 1usize;
                         let mut __fd_offset = 0usize;
                         #(#write_tmps)*
@@ -344,14 +382,13 @@ fn define_write_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
             Fields::Unit => {
                 let v = quote! {
                     #name::#variant_name => {
-                        buffer[0] = #i;
+                        buffer[0] = #idx;
                         Ok(0)
                     }
                 };
                 match_variants.push(v);
             }
         }
-        i += 1;
     }
 
     quote! {
@@ -360,6 +397,9 @@ fn define_write_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
             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)*
             }
@@ -367,24 +407,25 @@ fn define_write_buffer_for_enum(name: &Ident, de: &DataEnum) -> TokenStream {
     }
 }
 
-fn enum_write_to_buffer_and_move_offset(name: &Ident, ty: &syn::Type) -> TokenStream {
+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 += <#ty>::msg_size();
+        __offset += #name.msg_size();
         __fd_offset += o;
     }
 }
 
 /************************** Tuple Impls ********************************************/
 fn impl_for_tuple_struct(name: Ident, ds: DataStruct) -> TokenStream {
-    let types = get_tuple_types(ds);
+    let fields = get_tuple_fields(ds);
 
-    let buffer_sizes_impls = define_buffer_size_for_struct(&types);
-
-    let read_buffer = define_read_buffer_for_tuples(&name, &types);
-    let write_buffer = define_write_buffer_for_tuples(&name, &types);
+    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
@@ -392,28 +433,42 @@ fn impl_for_tuple_struct(name: Ident, ds: DataStruct) -> TokenStream {
     }
 }
 
-fn get_tuple_types(ds: DataStruct) -> Vec<syn::Type> {
-    let mut types = Vec::new();
+fn get_tuple_fields(ds: DataStruct) -> Vec<(Member, Type)> {
+    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 field in fields {
-        let ty = field.ty;
-        types.push(ty);
+    for (idx, field) in fields.iter().enumerate() {
+        let member = Member::Unnamed(Index::from(idx));
+        let ty = field.ty.clone();
+        field_idents.push((member, ty));
+    }
+    field_idents
+}
+
+fn define_uses_fd_for_tuples(fields: &[(Member, Type)]) -> TokenStream {
+    if fields.len() == 0 {
+        return quote!();
+    }
+
+    let field_types = fields.iter().map(|(_, ty)| ty);
+    quote! {
+        fn uses_fd() -> bool {
+            #(<#field_types>::uses_fd())||*
+        }
     }
-    types
 }
 
-fn define_read_buffer_for_tuples(name: &Ident, fields: &[syn::Type]) -> TokenStream {
+fn define_read_buffer_for_tuples(name: &Ident, fields: &[(Member, Type)]) -> TokenStream {
     let mut read_fields = Vec::new();
     let mut init_fields = Vec::new();
-    for i in 0..fields.len() {
-        let tmp_name = format!("tuple_tmp{}", i);
+    for (idx, (_, field_ty)) 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, &fields[i]);
+        let read_field = read_from_buffer_and_move_offset(&tmp_name, field_ty);
         read_fields.push(read_field);
         init_fields.push(quote!(#tmp_name));
     }
@@ -436,13 +491,12 @@ fn define_read_buffer_for_tuples(name: &Ident, fields: &[syn::Type]) -> TokenStr
     }
 }
 
-fn define_write_buffer_for_tuples(name: &Ident, fields: &[syn::Type]) -> TokenStream {
+fn define_write_buffer_for_tuples(name: &Ident, fields: &[(Member, Type)]) -> TokenStream {
     let mut write_fields = Vec::new();
     let mut tmp_names = Vec::new();
-    for i in 0..fields.len() {
-        let tmp_name = format!("tuple_tmp{}", i);
-        let tmp_name = Ident::new(&tmp_name, Span::call_site());
-        let write_field = enum_write_to_buffer_and_move_offset(&tmp_name, &fields[i]);
+    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);
     }
@@ -461,14 +515,15 @@ fn define_write_buffer_for_tuples(name: &Ident, fields: &[syn::Type]) -> TokenSt
     }
 }
 /************************** Helpers ********************************************/
-fn get_fields_buffer_size_sum(field_types: &[syn::Type]) -> (TokenStream, TokenStream) {
-    if field_types.len() > 0 {
+fn get_fields_buffer_size_sum(fields: &[(Member, Type)]) -> (TokenStream, TokenStream) {
+    let fields: Vec<_> = fields.iter().map(|(m, _)| m).collect();
+    if fields.len() > 0 {
         (
             quote! {
-                #( <#field_types>::msg_size() as usize )+*
+                #( self.#fields.msg_size() as usize )+*
             },
             quote! {
-                #( <#field_types>::max_fd_count() as usize )+*
+                #( self.#fields.fd_count() as usize )+*
             },
         )
     } else {
@@ -476,19 +531,19 @@ fn get_fields_buffer_size_sum(field_types: &[syn::Type]) -> (TokenStream, TokenS
     }
 }
 
-fn read_from_buffer_and_move_offset(name: &Ident, ty: &syn::Type) -> TokenStream {
+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 += <#ty>::msg_size();
+        __offset += t.0.msg_size();
         __fd_offset += t.1;
         let #name = t.0;
     }
 }
 
-fn write_to_buffer_and_move_offset(name: &Ident, ty: &syn::Type) -> TokenStream {
+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 += <#ty>::msg_size();
+        __offset += self.#name.msg_size();
         __fd_offset += o;
     }
 }
@@ -511,15 +566,18 @@ mod tests {
 
         let expected = quote! {
             impl msg_socket::MsgOnSocket for MyMsg {
-                fn msg_size() -> usize {
-                    <u8>::msg_size() as usize
-                        + <RawFd>::msg_size() as usize
-                        + <u32>::msg_size() as usize
+                fn uses_fd() -> bool {
+                    <u8>::uses_fd() || <RawFd>::uses_fd() || <u32>::uses_fd()
                 }
-                fn max_fd_count() -> usize {
-                    <u8>::max_fd_count() as usize
-                        + <RawFd>::max_fd_count() as usize
-                        + <u32>::max_fd_count() as usize
+                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],
@@ -528,15 +586,15 @@ mod tests {
                     let mut __offset = 0usize;
                     let mut __fd_offset = 0usize;
                     let t = <u8>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
-                    __offset += <u8>::msg_size();
+                    __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 += <RawFd>::msg_size();
+                    __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 += <u32>::msg_size();
+                    __offset += t.0.msg_size();
                     __fd_offset += t.1;
                     let c = t.0;
                     Ok((Self { a, b, c }, __fd_offset))
@@ -548,21 +606,25 @@ mod tests {
                 ) -> msg_socket::MsgResult<usize> {
                     let mut __offset = 0usize;
                     let mut __fd_offset = 0usize;
-                    let o = self.a
+                    let o = self
+                        .a
                         .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
-                    __offset += <u8>::msg_size();
+                    __offset += self.a.msg_size();
                     __fd_offset += o;
-                    let o = self.b
+                    let o = self
+                        .b
                         .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
-                    __offset += <RawFd>::msg_size();
+                    __offset += self.b.msg_size();
                     __fd_offset += o;
-                    let o = self.c
+                    let o = self
+                        .c
                         .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
-                    __offset += <u32>::msg_size();
+                    __offset += self.c.msg_size();
                     __fd_offset += o;
                     Ok(__fd_offset)
                 }
             }
+
         };
 
         assert_eq!(msg_socket_impl(input).to_string(), expected.to_string());
@@ -576,15 +638,17 @@ mod tests {
 
         let expected = quote! {
             impl msg_socket::MsgOnSocket for MyMsg {
-                fn msg_size() -> usize {
-                    <u8>::msg_size() as usize
-                        + <u32>::msg_size() as usize
-                        + <File>::msg_size() as usize
+                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 max_fd_count() -> usize {
-                    <u8>::max_fd_count() as usize
-                        + <u32>::max_fd_count() as usize
-                        + <File>::max_fd_count() 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],
@@ -593,15 +657,15 @@ mod tests {
                     let mut __offset = 0usize;
                     let mut __fd_offset = 0usize;
                     let t = <u8>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
-                    __offset += <u8>::msg_size();
+                    __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 += <u32>::msg_size();
+                    __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 += <File>::msg_size();
+                    __offset += t.0.msg_size();
                     __fd_offset += t.1;
                     let tuple_tmp2 = t.0;
                     Ok((MyMsg(tuple_tmp0, tuple_tmp1, tuple_tmp2), __fd_offset))
@@ -614,17 +678,14 @@ mod tests {
                     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 += <u8>::msg_size();
+                    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 += <u32>::msg_size();
+                    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 += <File>::msg_size();
+                    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)
                 }
@@ -649,52 +710,50 @@ mod tests {
 
         let expected = quote! {
             impl msg_socket::MsgOnSocket for MyMsg {
-                fn msg_size() -> usize {
-                    [
-                        <u8>::msg_size() as usize,
-                        0,
-                        <u8>::msg_size() as usize + <RawFd>::msg_size() as usize,
-                    ].iter()
-                        .max().unwrap().clone() as usize+ 1
+                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 max_fd_count() -> usize {
-                    [
-                        <u8>::max_fd_count() as usize,
-                        0,
-                        <u8>::max_fd_count() as usize + <RawFd>::max_fd_count() as usize,
-                    ].iter()
-                        .max().unwrap().clone() as usize
+                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[0];
+                    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 += <u8>::msg_size();
+                            let t = <u8>::read_from_buffer(&buffer[__offset..], &fds[__fd_offset..])?;
+                            __offset += t.0.msg_size();
                             __fd_offset += t.1;
-                            let enum_variant_tmp0 = t.0;
-                            Ok((MyMsg::A(enum_variant_tmp0), __fd_offset))
+                            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 += <u8>::msg_size();
+                            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 += <RawFd>::msg_size();
+                            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))
@@ -707,14 +766,17 @@ mod tests {
                     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_variant_tmp0) => {
+                        MyMsg::A(enum_field0) => {
                             buffer[0] = 0u8;
                             let mut __offset = 1usize;
                             let mut __fd_offset = 0usize;
-                            let o = enum_variant_tmp0
+                            let o = enum_field0
                                 .write_to_buffer(&mut buffer[__offset..], &mut fds[__fd_offset..])?;
-                            __offset += <u8>::msg_size();
+                            __offset += enum_field0.msg_size();
                             __fd_offset += o;
                             Ok(__fd_offset)
                         }
@@ -726,20 +788,17 @@ mod tests {
                             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 += <u8>::msg_size();
+                            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 += <RawFd>::msg_size();
+                            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!(msg_socket_impl(input).to_string(), expected.to_string());
diff --git a/msg_socket/src/lib.rs b/msg_socket/src/lib.rs
index ea817f0..5871735 100644
--- a/msg_socket/src/lib.rs
+++ b/msg_socket/src/lib.rs
@@ -127,8 +127,8 @@ impl<M: MsgOnSocket> AsRawFd for Receiver<M> {
 pub trait MsgSender: AsRef<UnixSeqpacket> {
     type M: MsgOnSocket;
     fn send(&self, msg: &Self::M) -> MsgResult<()> {
-        let msg_size = Self::M::msg_size();
-        let fd_size = Self::M::max_fd_count();
+        let msg_size = msg.msg_size();
+        let fd_size = msg.fd_count();
         let mut msg_buffer: Vec<u8> = vec![0; msg_size];
         let mut fd_buffer: Vec<RawFd> = vec![0; fd_size];
 
@@ -149,34 +149,23 @@ pub trait MsgSender: AsRef<UnixSeqpacket> {
 pub trait MsgReceiver: AsRef<UnixSeqpacket> {
     type M: MsgOnSocket;
     fn recv(&self) -> MsgResult<Self::M> {
-        let msg_size = Self::M::msg_size();
-        let fd_size = Self::M::max_fd_count();
-
         let sock: &UnixSeqpacket = self.as_ref();
 
         let (msg_buffer, fd_buffer) = {
-            if fd_size == 0 {
+            if Self::M::uses_fd() {
+                sock.recv_as_vec_with_fds()
+                    .map_err(|e| MsgError::Recv(SysError::new(e.raw_os_error().unwrap_or(0))))?
+            } else {
                 (
                     sock.recv_as_vec().map_err(|e| {
                         MsgError::Recv(SysError::new(e.raw_os_error().unwrap_or(0)))
                     })?,
                     vec![],
                 )
-            } else {
-                sock.recv_as_vec_with_fds()
-                    .map_err(|e| MsgError::Recv(SysError::new(e.raw_os_error().unwrap_or(0))))?
             }
         };
-
-        if msg_size != msg_buffer.len() {
-            return Err(MsgError::BadRecvSize {
-                expected: msg_size,
-                actual: msg_buffer.len(),
-            });
-        }
         // Safe because fd buffer is read from socket.
-        let (v, read_fd_size) =
-            unsafe { Self::M::read_from_buffer(&msg_buffer[..], &fd_buffer[..])? };
+        let (v, read_fd_size) = unsafe { Self::M::read_from_buffer(&msg_buffer, &fd_buffer)? };
         if fd_buffer.len() != read_fd_size {
             return Err(MsgError::NotExpectFd);
         }
diff --git a/msg_socket/src/msg_on_socket.rs b/msg_socket/src/msg_on_socket.rs
index 020f70f..624d514 100644
--- a/msg_socket/src/msg_on_socket.rs
+++ b/msg_socket/src/msg_on_socket.rs
@@ -4,9 +4,11 @@
 
 use std::fmt::{self, Display};
 use std::fs::File;
+use std::mem::{size_of, transmute_copy, MaybeUninit};
 use std::net::{TcpListener, TcpStream, UdpSocket};
 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
 use std::os::unix::net::{UnixDatagram, UnixListener, UnixStream};
+use std::ptr::drop_in_place;
 use std::result;
 
 use data_model::*;
@@ -90,10 +92,24 @@ impl Display for MsgError {
 /// Thus, read/write functions always the return correct count of fds in this variant. There will be
 /// no padding in fd_buffer.
 pub trait MsgOnSocket: Sized {
+    // `true` if this structure can potentially serialize fds.
+    fn uses_fd() -> bool {
+        false
+    }
+
+    // Returns `Some(size)` if this structure always has a fixed size.
+    fn fixed_size() -> Option<usize> {
+        None
+    }
+
     /// Size of message in bytes.
-    fn msg_size() -> usize;
-    /// Max possible fd count in this type.
-    fn max_fd_count() -> usize {
+    fn msg_size(&self) -> usize {
+        Self::fixed_size().unwrap()
+    }
+
+    /// Number of FDs in this message. This must be overridden if `uses_fd()` returns true.
+    fn fd_count(&self) -> usize {
+        assert!(!Self::uses_fd());
         0
     }
     /// Returns (self, fd read count).
@@ -104,13 +120,14 @@ pub trait MsgOnSocket: Sized {
     /// 2. write_to_buffer is implemented correctly (put valid fds into the buffer, has no padding,
     ///    return correct count).
     unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)>;
+
     /// Serialize self to buffers.
     fn write_to_buffer(&self, buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize>;
 }
 
 impl MsgOnSocket for SysError {
-    fn msg_size() -> usize {
-        u32::msg_size()
+    fn fixed_size() -> Option<usize> {
+        Some(size_of::<u32>())
     }
     unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
         let (v, size) = u32::read_from_buffer(buffer, fds)?;
@@ -123,12 +140,14 @@ impl MsgOnSocket for SysError {
 }
 
 impl MsgOnSocket for RawFd {
-    fn msg_size() -> usize {
-        0
+    fn fixed_size() -> Option<usize> {
+        Some(0)
     }
-    fn max_fd_count() -> usize {
+
+    fn fd_count(&self) -> usize {
         1
     }
+
     unsafe fn read_from_buffer(_buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
         if fds.is_empty() {
             return Err(MsgError::ExpectFd);
@@ -145,12 +164,22 @@ impl MsgOnSocket for RawFd {
 }
 
 impl<T: MsgOnSocket> MsgOnSocket for Option<T> {
-    fn msg_size() -> usize {
-        T::msg_size() + 1
+    fn uses_fd() -> bool {
+        T::uses_fd()
+    }
+
+    fn msg_size(&self) -> usize {
+        match self {
+            Some(v) => v.msg_size() + 1,
+            None => 0,
+        }
     }
 
-    fn max_fd_count() -> usize {
-        T::max_fd_count()
+    fn fd_count(&self) -> usize {
+        match self {
+            Some(v) => v.fd_count(),
+            None => 0,
+        }
     }
 
     unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
@@ -179,12 +208,8 @@ impl<T: MsgOnSocket> MsgOnSocket for Option<T> {
 }
 
 impl MsgOnSocket for () {
-    fn msg_size() -> usize {
-        0
-    }
-
-    fn max_fd_count() -> usize {
-        0
+    fn fixed_size() -> Option<usize> {
+        Some(0)
     }
 
     unsafe fn read_from_buffer(_buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
@@ -199,17 +224,20 @@ impl MsgOnSocket for () {
 macro_rules! rawfd_impl {
     ($type:ident) => {
         impl MsgOnSocket for $type {
-            fn msg_size() -> usize {
+            fn uses_fd() -> bool {
+                true
+            }
+            fn msg_size(&self) -> usize {
                 0
             }
-            fn max_fd_count() -> usize {
+            fn fd_count(&self) -> usize {
                 1
             }
             unsafe fn read_from_buffer(_buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
                 if fds.len() < 1 {
                     return Err(MsgError::ExpectFd);
                 }
-                Ok(($type::from_raw_fd(fds[0].clone()), 1))
+                Ok(($type::from_raw_fd(fds[0]), 1))
             }
             fn write_to_buffer(&self, _buffer: &mut [u8], fds: &mut [RawFd]) -> MsgResult<usize> {
                 if fds.len() < 1 {
@@ -247,11 +275,11 @@ where
 
 // usize could be different sizes on different targets. We always use u64.
 impl MsgOnSocket for usize {
-    fn msg_size() -> usize {
-        std::mem::size_of::<u64>()
+    fn msg_size(&self) -> usize {
+        size_of::<u64>()
     }
     unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
-        if buffer.len() < std::mem::size_of::<u64>() {
+        if buffer.len() < size_of::<u64>() {
             return Err(MsgError::WrongMsgBufferSize);
         }
         let t = u64::from_le_bytes(slice_to_array(buffer));
@@ -259,22 +287,22 @@ impl MsgOnSocket for usize {
     }
 
     fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
-        if buffer.len() < std::mem::size_of::<u64>() {
+        if buffer.len() < size_of::<u64>() {
             return Err(MsgError::WrongMsgBufferSize);
         }
         let t: Le64 = (*self as u64).into();
-        buffer[0..Self::msg_size()].copy_from_slice(t.as_slice());
+        buffer[0..self.msg_size()].copy_from_slice(t.as_slice());
         Ok(0)
     }
 }
 
 // Encode bool as a u8 of value 0 or 1
 impl MsgOnSocket for bool {
-    fn msg_size() -> usize {
-        std::mem::size_of::<u8>()
+    fn msg_size(&self) -> usize {
+        size_of::<u8>()
     }
     unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
-        if buffer.len() < std::mem::size_of::<u8>() {
+        if buffer.len() < size_of::<u8>() {
             return Err(MsgError::WrongMsgBufferSize);
         }
         let t: u8 = buffer[0];
@@ -285,7 +313,7 @@ impl MsgOnSocket for bool {
         }
     }
     fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
-        if buffer.len() < std::mem::size_of::<u8>() {
+        if buffer.len() < size_of::<u8>() {
             return Err(MsgError::WrongMsgBufferSize);
         }
         buffer[0] = *self as u8;
@@ -296,11 +324,12 @@ impl MsgOnSocket for bool {
 macro_rules! le_impl {
     ($type:ident, $native_type:ident) => {
         impl MsgOnSocket for $type {
-            fn msg_size() -> usize {
-                std::mem::size_of::<$native_type>()
+            fn fixed_size() -> Option<usize> {
+                Some(size_of::<$native_type>())
             }
+
             unsafe fn read_from_buffer(buffer: &[u8], _fds: &[RawFd]) -> MsgResult<(Self, usize)> {
-                if buffer.len() < std::mem::size_of::<$native_type>() {
+                if buffer.len() < size_of::<$native_type>() {
                     return Err(MsgError::WrongMsgBufferSize);
                 }
                 let t = $native_type::from_le_bytes(slice_to_array(buffer));
@@ -308,11 +337,11 @@ macro_rules! le_impl {
             }
 
             fn write_to_buffer(&self, buffer: &mut [u8], _fds: &mut [RawFd]) -> MsgResult<usize> {
-                if buffer.len() < std::mem::size_of::<$native_type>() {
+                if buffer.len() < size_of::<$native_type>() {
                     return Err(MsgError::WrongMsgBufferSize);
                 }
                 let t: $native_type = self.clone().into();
-                buffer[0..Self::msg_size()].copy_from_slice(&t.to_le_bytes());
+                buffer[0..self.msg_size()].copy_from_slice(&t.to_le_bytes());
                 Ok(0)
             }
         }
@@ -332,30 +361,85 @@ macro_rules! array_impls {
     ($N:expr, $t: ident $($ts:ident)*)
     => {
         impl<T: MsgOnSocket> MsgOnSocket for [T; $N] {
-            fn msg_size() -> usize {
-                T::msg_size() * $N
+            fn uses_fd() -> bool {
+                T::uses_fd()
             }
-            fn max_fd_count() -> usize {
-                T::max_fd_count() * $N
+
+            fn fixed_size() -> Option<usize> {
+                Some(T::fixed_size()? * $N)
             }
-            unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
-                if buffer.len() < Self::msg_size() {
-                    return Err(MsgError::WrongMsgBufferSize);
+
+            fn msg_size(&self) -> usize {
+                match T::fixed_size() {
+                    Some(s) => s * $N,
+                    None => self.iter().map(|i| i.msg_size()).sum::<usize>() + size_of::<u64>() * $N
                 }
+            }
+
+            fn fd_count(&self) -> usize {
+                if T::uses_fd() {
+                    self.iter().map(|i| i.fd_count()).sum()
+                } else {
+                    0
+                }
+            }
+
+            unsafe fn read_from_buffer(buffer: &[u8], fds: &[RawFd]) -> MsgResult<(Self, usize)> {
+                // Taken from the canonical example of initializing an array, the `assume_init` can
+                // be assumed safe because the array elements (`MaybeUninit<T>` in this case)
+                // themselves don't require initializing.
+                let mut msgs: [MaybeUninit<T>; $N] =  MaybeUninit::uninit().assume_init();
+
                 let mut offset = 0usize;
                 let mut fd_offset = 0usize;
-                let ($t, fd_size) =
-                    T::read_from_buffer(&buffer[offset..], &fds[fd_offset..])?;
-                offset += T::msg_size();
-                fd_offset += fd_size;
-                $(
-                    let ($ts, fd_size) =
-                        T::read_from_buffer(&buffer[offset..], &fds[fd_offset..])?;
-                    offset += T::msg_size();
-                    fd_offset += fd_size;
-                    )*
-                assert_eq!(offset, Self::msg_size());
-                Ok(([$t, $($ts),*], fd_offset))
+
+                // In case of an error, we need to keep track of how many elements got initialized.
+                // In order to perform the necessary drops, the below loop is executed in a closure
+                // to capture errors without returning.
+                let mut last_index = 0;
+                let res = (|| {
+                    for msg in &mut msgs[..] {
+                        let element_size = match T::fixed_size() {
+                            Some(s) => s,
+                            None => {
+                                let (element_size, _) = u64::read_from_buffer(&buffer[offset..], &[])?;
+                                offset += element_size.msg_size();
+                                element_size as usize
+                            }
+                        };
+                        let (m, fd_size) =
+                            T::read_from_buffer(&buffer[offset..], &fds[fd_offset..])?;
+                        *msg = MaybeUninit::new(m);
+                        offset += element_size;
+                        fd_offset += fd_size;
+                        last_index += 1;
+                    }
+                    Ok(())
+                })();
+
+                // Because `MaybeUninit` will not automatically call drops, we have to drop the
+                // partially initialized array manually in the case of an error.
+                if let Err(e) = res {
+                    for msg in &mut msgs[..last_index] {
+                        // The call to `as_mut_ptr()` turns the `MaybeUninit` element of the array
+                        // into a pointer, which can be used with `drop_in_place` to call the
+                        // destructor without moving the element, which is impossible. This is safe
+                        // because `last_index` prevents this loop from traversing into the
+                        // uninitialized parts of the array.
+                        drop_in_place(msg.as_mut_ptr());
+                    }
+                    return Err(e)
+                }
+
+                // Also taken from the canonical example, we initialized every member of the array
+                // in the first loop of this function, so it is safe to `transmute_copy` the array
+                // of `MaybeUninit` data to plain data. Although `transmute`, which checks the
+                // types' sizes, would have been preferred in this code, the compiler complains with
+                // "cannot transmute between types of different sizes, or dependently-sized types."
+                // Because this function operates on generic data, the type is "dependently-sized"
+                // and so the compiler will not check that the size of the input and output match.
+                // See this issue for details: https://github.com/rust-lang/rust/issues/61956
+                Ok((transmute_copy::<_, [T; $N]>(&msgs), fd_offset))
             }
 
             fn write_to_buffer(
@@ -363,21 +447,53 @@ macro_rules! array_impls {
                 buffer: &mut [u8],
                 fds: &mut [RawFd],
                 ) -> MsgResult<usize> {
-                if buffer.len() < Self::msg_size() {
-                    return Err(MsgError::WrongMsgBufferSize);
-                }
                 let mut offset = 0usize;
                 let mut fd_offset = 0usize;
                 for idx in 0..$N {
+                    let element_size = match T::fixed_size() {
+                        Some(s) => s,
+                        None => {
+                            let element_size = self[idx].msg_size() as u64;
+                            element_size.write_to_buffer(&mut buffer[offset..], &mut [])?;
+                            offset += element_size.msg_size();
+                            element_size as usize
+                        }
+                    };
                     let fd_size = self[idx].write_to_buffer(&mut buffer[offset..],
                                                             &mut fds[fd_offset..])?;
-                    offset += T::msg_size();
+                    offset += element_size;
                     fd_offset += fd_size;
                 }
 
                 Ok(fd_offset)
             }
         }
+        #[cfg(test)]
+        mod $t {
+            use super::MsgOnSocket;
+
+            #[test]
+            fn read_write_option_array() {
+                type ArrayType = [Option<u32>; $N];
+                let array = [Some($N); $N];
+                let mut buffer = vec![0; array.msg_size()];
+                array.write_to_buffer(&mut buffer, &mut []).unwrap();
+                let read_array = unsafe { ArrayType::read_from_buffer(&buffer, &[]) }.unwrap().0;
+
+                assert_eq!(array, read_array);
+            }
+
+            #[test]
+            fn read_write_fixed() {
+                type ArrayType = [u32; $N];
+                let mut buffer = vec![0; <ArrayType>::fixed_size().unwrap()];
+                let array = [$N as u32; $N];
+                array.write_to_buffer(&mut buffer, &mut []).unwrap();
+                let read_array = unsafe { ArrayType::read_from_buffer(&buffer, &[]) }.unwrap().0;
+
+                assert_eq!(array, read_array);
+            }
+        }
         array_impls!(($N - 1), $($ts)*);
     };
     {$N:expr, } => {};