diff --git a/ipc/codegen/src/serialization.rs b/ipc/codegen/src/serialization.rs index c2efc96c7..1c8fa32af 100644 --- a/ipc/codegen/src/serialization.rs +++ b/ipc/codegen/src/serialization.rs @@ -104,13 +104,17 @@ fn serialize_item( $size_expr } - fn to_bytes(&self, buffer: &mut [u8]) -> Result<(), BinaryConvertError> { + fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> { $write_expr } - fn from_bytes(buffer: &[u8]) -> Result { + fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result { $read_expr } + + fn len_params() -> usize { + 1 + } } ).unwrap()) } @@ -158,23 +162,6 @@ struct BinaryExpressions { pub read: P, } -fn is_variable_size(ty: &P) -> bool { - match ty.node { - TyKind::Vec(_) => true, - TyKind::FixedLengthVec(_, _) => false, - TyKind::Path(_, ref path) => { - path.segments[0].identifier.name.as_str() == "Option" || - path.segments[0].identifier.name.as_str() == "Result" || - path.segments[0].identifier.name.as_str() == "String" - }, - _ => { false } - } -} - -fn variable_sizes(cx: &ExtCtxt, fields: &[ast::StructField]) -> Vec { - fields.iter().map(|field| is_variable_size(&field.ty)).collect::>() -} - fn binary_expr_struct( cx: &ExtCtxt, builder: &aster::AstBuilder, @@ -183,24 +170,26 @@ fn binary_expr_struct( value_ident: Option, instance_ident: Option, ) -> Result { - let variable_sizes = variable_size_indexes(fields); let size_exprs: Vec> = fields.iter().enumerate().map(|(index, field)| { - if variable_sizes[index] { - let index_ident = builder.id(format!("__field{}", index)); - value_ident.and_then(|x| { - let field_id = builder.id(field.ident.unwrap()); - Some(quote_expr!(cx, $x . $field_id .size())) - }) - .unwrap_or_else(|| quote_expr!(cx, $index_ident .size())) - } - else { - let field_type_ident = builder.id(&::syntax::print::pprust::ty_to_string(&field.ty)); - quote_expr!(cx, mem::sizeof_of::()); - } + let field_type_ident = builder.id(&::syntax::print::pprust::ty_to_string(&field.ty)); + let index_ident = builder.id(format!("__field{}", index)); + value_ident.and_then(|x| { + let field_id = builder.id(field.ident.unwrap()); + Some(quote_expr!(cx, + match $field_type_ident::len_params() { + 0 => mem::size_of::<$field_type_ident>(), + _ => $x. $field_id .size() + })) + }) + .unwrap_or_else(|| quote_expr!(cx, match $field_type_ident::len_params() { + 0 => mem::size_of::<$field_type_ident>(), + _ => $index_ident .size() + })) }).collect(); - let mut total_size_expr = size_exprs[0].clone(); + let first_size_expr = size_exprs[0].clone(); + let mut total_size_expr = quote_expr!(cx, 0usize + $first_size_expr); for index in 1..size_exprs.len() { let next_expr = size_exprs[index].clone(); total_size_expr = quote_expr!(cx, $total_size_expr + $next_expr); @@ -215,25 +204,36 @@ fn binary_expr_struct( map_stmts.push(quote_stmt!(cx, let mut total = 0usize;).unwrap()); for (index, field) in fields.iter().enumerate() { let size_expr = &size_exprs[index]; - write_stmts.push(quote_stmt!(cx, let next_line = offset + $size_expr; ).unwrap()); - match value_ident { + let field_type_ident = builder.id(&::syntax::print::pprust::ty_to_string(&field.ty)); + + let member_expr = match value_ident { Some(x) => { let field_id = builder.id(field.ident.unwrap()); - write_stmts.push( - quote_stmt!(cx, $x . $field_id .to_bytes(&mut buffer[offset..next_line]);).unwrap()) + quote_expr!(cx, $x . $field_id) }, None => { let index_ident = builder.id(format!("__field{}", index)); - write_stmts.push( - quote_stmt!(cx, $index_ident .to_bytes(&mut buffer[offset..next_line]);).unwrap()) + quote_expr!(cx, $index_ident) } - } + }; + + write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident::len_params() { + 0 => mem::size_of::<$field_type_ident>(), + _ => { let size = $member_expr .size(); length_stack.push_back(size); size } + }).unwrap()); + + write_stmts.push(quote_stmt!(cx, + $member_expr .to_bytes(&mut buffer[offset..next_line], length_stack);).unwrap()); + write_stmts.push(quote_stmt!(cx, offset = next_line; ).unwrap()); let field_index = builder.id(&format!("{}", index)); - let field_type_ident = builder.id(&::syntax::print::pprust::ty_to_string(&field.ty)); map_stmts.push(quote_stmt!(cx, map[$field_index] = total;).unwrap()); - map_stmts.push(quote_stmt!(cx, total = total + mem::size_of::<$field_type_ident>();).unwrap()); + map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident::len_params() { + 0 => mem::size_of::<$field_type_ident>(), + _ => length_stack.pop_front().unwrap() + }).unwrap()); + map_stmts.push(quote_stmt!(cx, total = total + size;).unwrap()); }; let read_expr = if value_ident.is_some() { @@ -386,6 +386,10 @@ fn fields_sequence( tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)), token::Plain))); tt.push(Token(_sp, token::CloseDelim(token::Bracket))); tt.push(Token(_sp, token::CloseDelim(token::Bracket))); + + tt.push(Token(_sp, token::Comma)); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("length_stack"), token::Plain))); + tt.push(Token(_sp, token::CloseDelim(token::Paren))); tt.push(Token(_sp, token::CloseDelim(token::Paren))); tt.push(Token(_sp, token::Comma)); @@ -450,8 +454,14 @@ fn named_fields_sequence( tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"), token::Plain))); tt.push(Token(_sp, token::OpenDelim(token::Bracket))); tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)), token::Plain))); + tt.push(Token(_sp, token::CloseDelim(token::Bracket))); tt.push(Token(_sp, token::CloseDelim(token::Bracket))); + + tt.push(Token(_sp, token::Comma)); + tt.push(Token(_sp, token::Ident(ext_cx.ident_of("length_stack"), token::Plain))); + + tt.push(Token(_sp, token::CloseDelim(token::Paren))); tt.push(Token(_sp, token::CloseDelim(token::Paren))); tt.push(Token(_sp, token::Comma)); diff --git a/ipc/tests/binary.rs.in b/ipc/tests/binary.rs.in index 028fb9800..c3dd224b2 100644 --- a/ipc/tests/binary.rs.in +++ b/ipc/tests/binary.rs.in @@ -16,16 +16,17 @@ use ipc::*; use std::mem; +use std::collections::VecDeque; #[derive(Binary)] -enum Root { +pub enum Root { Top, Middle(u32, u64), } -#[derive(Binary)] -struct DoubleRoot { - x1: u32, - x2: u64, - x3: u32, +#[derive(Binary, PartialEq, Debug)] +pub struct DoubleRoot { + pub x1: u32, + pub x2: u64, + pub x3: u32, } diff --git a/ipc/tests/examples.rs b/ipc/tests/examples.rs index 5a4324ec4..f20cba793 100644 --- a/ipc/tests/examples.rs +++ b/ipc/tests/examples.rs @@ -18,6 +18,7 @@ mod tests { use super::super::service::*; + use super::super::binary::*; use super::super::nested::{DBClient,DBWriter}; use ipc::*; use devtools::*; @@ -143,4 +144,19 @@ mod tests { assert!(result.is_ok()); } + + #[test] + fn can_serialize_dummy_structs() { + let mut socket = TestSocket::new(); + + let struct_ = DoubleRoot { x1: 0, x2: 100, x3: 100000}; + let res = ::ipc::binary::serialize_into(&struct_, &mut socket); + + assert!(res.is_ok()); + + let mut read_socket = TestSocket::new_ready(socket.write_buffer.clone()); + let new_struct: DoubleRoot = ::ipc::binary::deserialize_from(&mut read_socket).unwrap(); + + assert_eq!(struct_, new_struct); + } }