diff --git a/ipc/codegen/src/serialization.rs b/ipc/codegen/src/serialization.rs index 1af35422c..c2efc96c7 100644 --- a/ipc/codegen/src/serialization.rs +++ b/ipc/codegen/src/serialization.rs @@ -28,6 +28,7 @@ use syntax::ast::{ TraitRef, Ident, Generics, + TyKind, }; use syntax::ast; @@ -157,6 +158,23 @@ 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, @@ -165,13 +183,21 @@ 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)| { - 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())) + 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::()); + } }).collect(); let mut total_size_expr = size_exprs[0].clone(); diff --git a/ipc/rpc/src/binary.rs b/ipc/rpc/src/binary.rs index 02f0da954..61eb9277f 100644 --- a/ipc/rpc/src/binary.rs +++ b/ipc/rpc/src/binary.rs @@ -16,17 +16,21 @@ //! Binary representation of types -use util::bytes::*; +use util::bytes::Populatable; use std::mem; +use std::collections::VecDeque; +#[derive(Debug)] pub struct BinaryConvertError; pub trait BinaryConvertable : Sized { - fn size(&self) -> usize; + fn size(&self) -> usize { + mem::size_of::() + } - fn to_bytes(&self, buffer: &mut [u8]) -> Result<(), BinaryConvertError>; + fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError>; - fn from_bytes(buffer: &[u8]) -> Result; + fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result; fn from_empty_bytes() -> Result { Err(BinaryConvertError) @@ -42,12 +46,12 @@ impl BinaryConvertable for Option where T: BinaryConvertable { match * self { None => 0, Some(ref val) => val.size() } } - fn to_bytes(&self, buffer: &mut [u8]) -> Result<(), BinaryConvertError> { - match *self { None => Err(BinaryConvertError), Some(ref val) => val.to_bytes(buffer) } + fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> { + match *self { None => Err(BinaryConvertError), Some(ref val) => val.to_bytes(buffer, length_stack) } } - fn from_bytes(buffer: &[u8]) -> Result { - Ok(Some(try!(T::from_bytes(buffer)))) + fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result { + Ok(Some(try!(T::from_bytes(buffer, length_stack)))) } fn from_empty_bytes() -> Result { @@ -67,18 +71,52 @@ impl BinaryConvertable for Vec where T: BinaryConvertable { } } - fn to_bytes(&self, buffer: &mut [u8]) -> Result<(), BinaryConvertError> { + fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> { let mut offset = 0usize; - for (index, item) in self.iter().enumerate() { - let item_end = offset + item.size(); - try!(item.to_bytes(&mut buffer[offset..item_end])); - offset = item_end; + for item in self.iter() { + let next_size = match T::len_params() { + 0 => mem::size_of::(), + _ => { let size = item.size(); length_stack.push_back(size); size }, + }; + if next_size > 0 { + let item_end = offset + next_size; + try!(item.to_bytes(&mut buffer[offset..item_end], length_stack)); + offset = item_end; + } } Ok(()) } - fn from_bytes(buffer: &[u8]) -> Result { - Err(BinaryConvertError) + fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result { + let mut index = 0; + let mut result = Self::with_capacity( + match T::len_params() { + 0 => buffer.len() / mem::size_of::(), + _ => 128, + }); + + loop { + let next_size = match T::len_params() { + 0 => mem::size_of::(), + _ => try!(length_stack.pop_front().ok_or(BinaryConvertError)), + }; + let item = if next_size == 0 { + try!(T::from_empty_bytes()) + } + else { + try!(T::from_bytes(&buffer[index..index+next_size], length_stack)) + }; + result.push(item); + + index = index + next_size; + if index == buffer.len() { break; } + if index > buffer.len() { + return Err(BinaryConvertError) + } + + } + + Ok(result) } fn from_empty_bytes() -> Result { @@ -90,14 +128,79 @@ impl BinaryConvertable for Vec where T: BinaryConvertable { } } +pub fn deserialize_from(r: &mut R) -> Result + where R: ::std::io::Read, + T: BinaryConvertable +{ + let mut fake_stack = VecDeque::new(); + let mut length_stack = VecDeque::::new(); + let mut size_buffer = [0u8; 8]; + try!(r.read(&mut size_buffer[..]).map_err(|_| BinaryConvertError)); + let stack_len = try!(u64::from_bytes(&mut size_buffer[..], &mut fake_stack)) as usize; + if stack_len > 0 { + let mut header_buffer = Vec::with_capacity(stack_len * 8); + unsafe { header_buffer.set_len(stack_len * 8); }; + + try!(r.read(&mut header_buffer[..]).map_err(|_| BinaryConvertError)); + for idx in 0..stack_len { + let stack_item = try!(u64::from_bytes(&header_buffer[idx*8..(idx+1)*8], &mut fake_stack)); + length_stack.push_back(stack_item as usize); + } + } + + try!(r.read(&mut size_buffer[..]).map_err(|_| BinaryConvertError)); + let size = try!(u64::from_bytes(&size_buffer[..], &mut fake_stack)) as usize; + + let mut data = Vec::with_capacity(size); + unsafe { data.set_len(size) }; + try!(r.read(&mut data).map_err(|_| BinaryConvertError)); + + T::from_bytes(&data[..], &mut length_stack) +} + +pub fn serialize_into(t: &T, w: &mut W) -> Result<(), BinaryConvertError> + where W: ::std::io::Write, + T: BinaryConvertable +{ + let mut length_stack = VecDeque::::new(); + let mut fake_stack = VecDeque::new(); + let mut size_buffer = [0u8; 8]; + + let size = t.size(); + let mut buffer = Vec::with_capacity(size); + unsafe { buffer.set_len(size); } + try!(t.to_bytes(&mut buffer[..], &mut length_stack)); + + let stack_len = length_stack.len(); + try!((stack_len as u64).to_bytes(&mut size_buffer[..], &mut fake_stack)); + try!(w.write(&size_buffer[..]).map_err(|_| BinaryConvertError)); + if stack_len > 0 { + let mut header_buffer = Vec::with_capacity(stack_len * 8); + unsafe { header_buffer.set_len(stack_len * 8); }; + try!((stack_len as u64).to_bytes(&mut header_buffer[0..8], &mut fake_stack)); + let mut idx = 0; + loop { + match length_stack.pop_front() { + Some(val) => try!((val as u64).to_bytes(&mut header_buffer[idx * 8..(idx+1) * 8], &mut fake_stack)), + None => { break; } + } + idx = idx + 1; + } + try!(w.write(&header_buffer[..]).map_err(|_| BinaryConvertError)); + } + + try!((size as u64).to_bytes(&mut size_buffer[..], &mut fake_stack)); + try!(w.write(&size_buffer[..]).map_err(|_| BinaryConvertError)); + + try!(w.write(&buffer[..]).map_err(|_| BinaryConvertError)); + + Ok(()) +} + macro_rules! binary_fixed_size { ($target_ty: ident) => { impl BinaryConvertable for $target_ty { - fn size(&self) -> usize { - mem::size_of::<$target_ty>() - } - - fn from_bytes(bytes: &[u8]) -> Result { + fn from_bytes(bytes: &[u8], _length_stack: &mut VecDeque) -> Result { match bytes.len().cmp(&::std::mem::size_of::<$target_ty>()) { ::std::cmp::Ordering::Less => return Err(BinaryConvertError), ::std::cmp::Ordering::Greater => return Err(BinaryConvertError), @@ -108,7 +211,7 @@ macro_rules! binary_fixed_size { Ok(res) } - fn to_bytes(&self, buffer: &mut [u8]) -> Result<(), BinaryConvertError> { + fn to_bytes(&self, buffer: &mut [u8], _length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> { let sz = ::std::mem::size_of::<$target_ty>(); let ip: *const $target_ty = self; let ptr: *const u8 = ip as *const _; @@ -124,3 +227,131 @@ macro_rules! binary_fixed_size { binary_fixed_size!(u64); binary_fixed_size!(u32); binary_fixed_size!(bool); + +#[test] +fn vec_serialize() { + let mut v = Vec::new(); + v.push(5u64); + v.push(10u64); + let mut length_stack = VecDeque::new(); + let mut data = Vec::with_capacity(v.size()); + unsafe { data.set_len(v.size()); } + let result = v.to_bytes(&mut data[..], &mut length_stack); + + assert!(result.is_ok()); + assert_eq!(5, data[0]); + assert_eq!(0, data[1]); + assert_eq!(10, data[8]); + assert_eq!(0, data[12]); +} + +#[test] +fn calculates_size() { + let mut v = Vec::new(); + v.push(5u64); + v.push(10u64); + + assert_eq!(16, v.size()); +} + +#[test] +fn vec_deserialize() { + let data = [ + 10u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 5u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ]; + + let mut length_stack = VecDeque::new(); + let vec = Vec::::from_bytes(&data[..], &mut length_stack).unwrap(); + + assert_eq!(vec![10u64, 5u64], vec); +} + +#[test] +fn vec_deserialize_chained() { + let mut v = Vec::new(); + v.push(Some(5u64)); + v.push(Some(10u64)); + v.push(None); + v.push(Some(12u64)); + + let mut length_stack = VecDeque::new(); + let mut data = Vec::with_capacity(v.size()); + unsafe { data.set_len(v.size()); } + let result = v.to_bytes(&mut data[..], &mut length_stack); + + assert!(result.is_ok()); + assert_eq!(4, length_stack.len()); +} + +#[test] +fn vec_serialize_deserialize() { + let mut v = Vec::new(); + v.push(Some(5u64)); + v.push(None); + v.push(Some(10u64)); + v.push(None); + v.push(Some(12u64)); + + + let mut data = Vec::with_capacity(v.size()); + unsafe { data.set_len(v.size()); } + let mut length_stack = VecDeque::new(); + + v.to_bytes(&mut data[..], &mut length_stack).unwrap(); + let de_v = Vec::>::from_bytes(&data[..], &mut length_stack).unwrap(); + + assert_eq!(v, de_v); +} + +#[test] +fn serialize_into_ok() { + use std::io::Cursor; + let mut buff = Cursor::new(vec![0; 128]); + + let mut v = Vec::new(); + v.push(Some(5u64)); + v.push(None); + v.push(Some(10u64)); + v.push(None); + v.push(Some(12u64)); + + serialize_into(&v, &mut buff).unwrap(); + assert_eq!(5, buff.get_ref()[0]); + assert_eq!(8, buff.get_ref()[8]); + assert_eq!(0, buff.get_ref()[16]); + assert_eq!(8, buff.get_ref()[24]); +} + +#[test] +fn deserialize_from_ok() { + use std::io::Cursor; + let mut buff = Cursor::new(vec![ + 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 16u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 10u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 5u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + ]); + + let vec = deserialize_from::, _>(&mut buff).unwrap(); + + assert_eq!(vec![10u64, 5u64], vec); +} + +#[test] +fn serialize_into_deserialize_from() { + use std::io::{Cursor, SeekFrom, Seek}; + + let mut buff = Cursor::new(vec![0u8; 1024]); + let mut v = Vec::new(); + v.push(Some(5u64)); + v.push(None); + v.push(Some(10u64)); + v.push(None); + v.push(Some(12u64)); + + serialize_into(&v, &mut buff).unwrap(); + buff.seek(SeekFrom::Start(0)).unwrap(); + let de_v = deserialize_from::>, _>(&mut buff).unwrap(); + assert_eq!(v, de_v); +}