diff options
author | Zach Reizner <zachr@google.com> | 2020-01-28 13:18:09 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-04-05 15:10:47 +0000 |
commit | 146450b4569e86657d1d8c4ffe17524781aae7e3 (patch) | |
tree | def385d4cf3e5c0e5f96169f8f9555800a9daadd /msg_socket | |
parent | 773c70740e98c1aaf73a7b02e65eadaeab33c9d8 (diff) | |
download | crosvm-146450b4569e86657d1d8c4ffe17524781aae7e3.tar crosvm-146450b4569e86657d1d8c4ffe17524781aae7e3.tar.gz crosvm-146450b4569e86657d1d8c4ffe17524781aae7e3.tar.bz2 crosvm-146450b4569e86657d1d8c4ffe17524781aae7e3.tar.lz crosvm-146450b4569e86657d1d8c4ffe17524781aae7e3.tar.xz crosvm-146450b4569e86657d1d8c4ffe17524781aae7e3.tar.zst crosvm-146450b4569e86657d1d8c4ffe17524781aae7e3.zip |
msg_socket: support dynamically sized types
This change is a major shift in how the MsgOnSocket trait works to allow `self` to be used to determine the result `msg_size()`. This is to support data structures with `Vec` or other dynamically sized type. TEST=./build_test cargo test -p msg_socket tast run <DUT> crostini.CopyPaste.* BUG=None Cq-Depend: chromium:2025907 Change-Id: Ibdb51b377b2a2a77892f6c75e1a9f30b2f8b0240 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2029930 Tested-by: Zach Reizner <zachr@chromium.org> Auto-Submit: Zach Reizner <zachr@chromium.org> Reviewed-by: Zach Reizner <zachr@chromium.org> Commit-Queue: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'msg_socket')
-rw-r--r-- | msg_socket/msg_on_socket_derive/msg_on_socket_derive.rs | 471 | ||||
-rw-r--r-- | msg_socket/src/lib.rs | 25 | ||||
-rw-r--r-- | msg_socket/src/msg_on_socket.rs | 234 |
3 files changed, 447 insertions, 283 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 3779357..fd6c19a 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!(socket_msg_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!(socket_msg_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 f03c36f..3f34019 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). @@ -103,13 +119,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)?; @@ -122,12 +139,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); @@ -144,12 +163,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)> { @@ -178,12 +207,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)> { @@ -198,17 +223,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 { @@ -246,11 +274,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)); @@ -258,22 +286,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]; @@ -284,7 +312,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; @@ -295,11 +323,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)); @@ -307,11 +336,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) } } @@ -331,30 +360,85 @@ macro_rules! array_impls { ($N:expr, $t: ident $($ts:ident)*) => { impl<T: MsgOnSocket + Clone> 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( @@ -362,21 +446,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 fd_size = self[idx].clone().write_to_buffer(&mut buffer[offset..], + 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, } => {}; |