finished with io
This commit is contained in:
parent
ffc10fec8b
commit
bb6d47d0cd
@ -28,6 +28,7 @@ use syntax::ast::{
|
||||
TraitRef,
|
||||
Ident,
|
||||
Generics,
|
||||
TyKind,
|
||||
};
|
||||
|
||||
use syntax::ast;
|
||||
@ -157,6 +158,23 @@ struct BinaryExpressions {
|
||||
pub read: P<ast::Expr>,
|
||||
}
|
||||
|
||||
fn is_variable_size(ty: &P<Ty>) -> 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<bool> {
|
||||
fields.iter().map(|field| is_variable_size(&field.ty)).collect::<Vec<bool>>()
|
||||
}
|
||||
|
||||
fn binary_expr_struct(
|
||||
cx: &ExtCtxt,
|
||||
builder: &aster::AstBuilder,
|
||||
@ -165,13 +183,21 @@ fn binary_expr_struct(
|
||||
value_ident: Option<ast::Ident>,
|
||||
instance_ident: Option<ast::Ident>,
|
||||
) -> Result<BinaryExpressions, Error> {
|
||||
let variable_sizes = variable_size_indexes(fields);
|
||||
|
||||
let size_exprs: Vec<P<ast::Expr>> = 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::<field_type_ident>());
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let mut total_size_expr = size_exprs[0].clone();
|
||||
|
@ -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::<Self>()
|
||||
}
|
||||
|
||||
fn to_bytes(&self, buffer: &mut [u8]) -> Result<(), BinaryConvertError>;
|
||||
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError>;
|
||||
|
||||
fn from_bytes(buffer: &[u8]) -> Result<Self, BinaryConvertError>;
|
||||
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError>;
|
||||
|
||||
fn from_empty_bytes() -> Result<Self, BinaryConvertError> {
|
||||
Err(BinaryConvertError)
|
||||
@ -42,12 +46,12 @@ impl<T> BinaryConvertable for Option<T> 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<usize>) -> Result<(), BinaryConvertError> {
|
||||
match *self { None => Err(BinaryConvertError), Some(ref val) => val.to_bytes(buffer, length_stack) }
|
||||
}
|
||||
|
||||
fn from_bytes(buffer: &[u8]) -> Result<Self, BinaryConvertError> {
|
||||
Ok(Some(try!(T::from_bytes(buffer))))
|
||||
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
|
||||
Ok(Some(try!(T::from_bytes(buffer, length_stack))))
|
||||
}
|
||||
|
||||
fn from_empty_bytes() -> Result<Self, BinaryConvertError> {
|
||||
@ -67,18 +71,52 @@ impl<T> BinaryConvertable for Vec<T> where T: BinaryConvertable {
|
||||
}
|
||||
}
|
||||
|
||||
fn to_bytes(&self, buffer: &mut [u8]) -> Result<(), BinaryConvertError> {
|
||||
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> 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::<T>(),
|
||||
_ => { 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<Self, BinaryConvertError> {
|
||||
Err(BinaryConvertError)
|
||||
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
|
||||
let mut index = 0;
|
||||
let mut result = Self::with_capacity(
|
||||
match T::len_params() {
|
||||
0 => buffer.len() / mem::size_of::<T>(),
|
||||
_ => 128,
|
||||
});
|
||||
|
||||
loop {
|
||||
let next_size = match T::len_params() {
|
||||
0 => mem::size_of::<T>(),
|
||||
_ => 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<Self, BinaryConvertError> {
|
||||
@ -90,14 +128,79 @@ impl<T> BinaryConvertable for Vec<T> where T: BinaryConvertable {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize_from<T, R>(r: &mut R) -> Result<T, BinaryConvertError>
|
||||
where R: ::std::io::Read,
|
||||
T: BinaryConvertable
|
||||
{
|
||||
let mut fake_stack = VecDeque::new();
|
||||
let mut length_stack = VecDeque::<usize>::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, W>(t: &T, w: &mut W) -> Result<(), BinaryConvertError>
|
||||
where W: ::std::io::Write,
|
||||
T: BinaryConvertable
|
||||
{
|
||||
let mut length_stack = VecDeque::<usize>::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<Self, BinaryConvertError> {
|
||||
fn from_bytes(bytes: &[u8], _length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
|
||||
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<usize>) -> 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::<u64>::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::<Option<u64>>::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::<Vec<u64>, _>(&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::<Vec<Option<u64>>, _>(&mut buff).unwrap();
|
||||
assert_eq!(v, de_v);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user