ethcore-db crate (#1097)

* trait

* implentated, lifetime issue still

* full api

* test mod

* working open

* get/retrieve

* fix warnings and bug

* working serialization of &[u8] parameters

* client attributes

* fix empty payload ser/de

* [ci skip] debug assert out

* extra deserialization test

* extra serialization test

* extra serialization test

* serialization fixes, nupdate rocksdb

* open test working

* result bug & remove some scaffolds

* fix warnings

* more simple tests

* consistent quotes

* get rid of dedicated is_open flag

* hashmap -> btreemap
This commit is contained in:
Nikolay Volf
2016-05-19 15:36:15 +03:00
committed by Gav Wood
parent 1946346711
commit dfac17538f
16 changed files with 809 additions and 85 deletions

View File

@@ -87,6 +87,13 @@ fn field_name(builder: &aster::AstBuilder, arg: &Arg) -> ast::Ident {
}
}
pub fn replace_slice_u8(builder: &aster::AstBuilder, ty: &P<ast::Ty>) -> P<ast::Ty> {
if ::syntax::print::pprust::ty_to_string(&strip_ptr(ty)) == "[u8]" {
return builder.ty().id("Vec<u8>")
}
ty.clone()
}
fn push_invoke_signature_aster(
builder: &aster::AstBuilder,
implement: &ImplItem,
@@ -111,8 +118,8 @@ fn push_invoke_signature_aster(
.attr().word("derive(Binary)")
.attr().word("allow(non_camel_case_types)")
.struct_(name_str.as_str())
.field(arg_name.as_str()).ty()
.build(strip_ptr(arg_ty));
.field(arg_name.as_str())
.ty().build(replace_slice_u8(builder, &strip_ptr(arg_ty)));
arg_names.push(arg_name);
arg_tys.push(arg_ty.clone());
@@ -120,7 +127,7 @@ fn push_invoke_signature_aster(
let arg_name = format!("{}", field_name(builder, &arg));
let arg_ty = &arg.ty;
tree = tree.field(arg_name.as_str()).ty().build(strip_ptr(arg_ty));
tree = tree.field(arg_name.as_str()).ty().build(replace_slice_u8(builder, &strip_ptr(arg_ty)));
arg_names.push(arg_name);
arg_tys.push(arg_ty.clone());
}
@@ -406,7 +413,7 @@ fn implement_client_method_body(
request_serialization_statements.push(
quote_stmt!(cx, let mut socket = socket_ref.deref_mut()));
request_serialization_statements.push(
quote_stmt!(cx, ::ipc::invoke($index_ident, Vec::new(), &mut socket)));
quote_stmt!(cx, ::ipc::invoke($index_ident, &None, &mut socket)));
request_serialization_statements
};

View File

@@ -175,30 +175,46 @@ fn binary_expr_struct(
) -> Result<BinaryExpressions, Error> {
let size_exprs: Vec<P<ast::Expr>> = fields.iter().enumerate().map(|(index, field)| {
if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" {
return quote_expr!(cx, 1);
}
let field_type_ident = builder.id(
&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)));
let field_type_ident_qualified = builder.id(
replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))));
let raw_ident = ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&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_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(),
_ => $x. $field_id .size(),
}))
})
.unwrap_or_else(|| quote_expr!(cx, match $field_type_ident_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(),
_ => $index_ident .size(),
}))
match raw_ident.as_ref() {
"u8" => {
quote_expr!(cx, 1)
},
"[u8]" => {
value_ident.and_then(|x| {
let field_id = builder.id(field.ident.unwrap());
Some(quote_expr!(cx, $x. $field_id .len()))
})
.unwrap_or_else(|| {
quote_expr!(cx, $index_ident .len())
}
)
}
_ => {
let field_type_ident = builder.id(
&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)));
let field_type_ident_qualified = builder.id(
replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))));
value_ident.and_then(|x|
{
let field_id = builder.id(field.ident.unwrap());
Some(quote_expr!(cx,
match $field_type_ident_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(),
_ => $x. $field_id .size(),
}))
})
.unwrap_or_else(|| {
quote_expr!(cx, match $field_type_ident_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(),
_ => $index_ident .size(),
})
})
}
}
}).collect();
let first_size_expr = size_exprs[0].clone();
@@ -233,17 +249,26 @@ fn binary_expr_struct(
},
};
if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" {
write_stmts.push(quote_stmt!(cx, let next_line = offset + 1;).unwrap());
write_stmts.push(quote_stmt!(cx, buffer[offset] = $member_expr; ).unwrap());
}
else {
write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident_qualified::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,
if let Err(e) = $member_expr .to_bytes(&mut buffer[offset..next_line], length_stack) { return Err(e) };).unwrap());
let raw_ident = ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty));
match raw_ident.as_ref() {
"u8" => {
write_stmts.push(quote_stmt!(cx, let next_line = offset + 1;).unwrap());
write_stmts.push(quote_stmt!(cx, buffer[offset] = $member_expr; ).unwrap());
},
"[u8]" => {
write_stmts.push(quote_stmt!(cx, let size = $member_expr .len();).unwrap());
write_stmts.push(quote_stmt!(cx, let next_line = offset + size;).unwrap());
write_stmts.push(quote_stmt!(cx, length_stack.push_back(size);).unwrap());
write_stmts.push(quote_stmt!(cx, buffer[offset..next_line].clone_from_slice($member_expr); ).unwrap());
}
_ => {
write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident_qualified::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,
if let Err(e) = $member_expr .to_bytes(&mut buffer[offset..next_line], length_stack) { return Err(e) };).unwrap());
}
}
write_stmts.push(quote_stmt!(cx, offset = next_line; ).unwrap());
@@ -251,15 +276,21 @@ fn binary_expr_struct(
let field_index = builder.id(&format!("{}", index));
map_stmts.push(quote_stmt!(cx, map[$field_index] = total;).unwrap());
if ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)) == "u8" {
map_stmts.push(quote_stmt!(cx, total += 1;).unwrap());
}
else {
map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(),
_ => length_stack.pop_front().unwrap(),
}).unwrap());
map_stmts.push(quote_stmt!(cx, total += size;).unwrap());
match raw_ident.as_ref() {
"u8" => {
map_stmts.push(quote_stmt!(cx, total = total + 1;).unwrap());
},
"[u8]" => {
map_stmts.push(quote_stmt!(cx, let size = length_stack.pop_front().unwrap();).unwrap());
map_stmts.push(quote_stmt!(cx, total = total + size;).unwrap());
},
_ => {
map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident_qualified::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());
}
}
};
@@ -419,6 +450,30 @@ fn fields_sequence(
continue;
}
// special case for [u8], it just takes a byte sequence
if ::syntax::print::pprust::ty_to_string(&field.ty) == "[u8]" {
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
tt.push(Token(_sp, token::DotDot));
if idx+1 != fields.len() {
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
}
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
tt.push(Token(_sp, token::Comma));
continue;
}
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!"))));
tt.push(Token(_sp, token::OpenDelim(token::Paren)));
tt.push(
@@ -513,6 +568,30 @@ fn named_fields_sequence(
continue;
}
// special case for [u8], it just takes a byte sequence
if ::syntax::print::pprust::ty_to_string(&field.ty) == "[u8]" {
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
tt.push(Token(_sp, token::DotDot));
if idx+1 != fields.len() {
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
}
tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
tt.push(Token(_sp, token::Comma));
continue;
}
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!"))));
tt.push(Token(_sp, token::OpenDelim(token::Paren)));
tt.push(Token(

View File

@@ -116,6 +116,8 @@ impl<S> Worker<S> where S: IpcInterface<S> {
/// Polls all sockets, reads and dispatches method invocations
pub fn poll(&mut self) {
use std::io::Write;
let mut request = PollRequest::new(&mut self.polls[..]);
let _result_guard = Socket::poll(&mut request, POLL_TIMEOUT);
@@ -135,7 +137,7 @@ impl<S> Worker<S> where S: IpcInterface<S> {
// dispatching for ipc interface
let result = self.service.dispatch_buf(method_num, payload);
if let Err(e) = socket.nb_write(&result) {
if let Err(e) = socket.write(&result) {
warn!(target: "ipc", "Failed to write response: {:?}", e);
}
}

View File

@@ -67,7 +67,7 @@ impl<T> BinaryConvertable for Option<T> where T: BinaryConvertable {
impl<E: BinaryConvertable> BinaryConvertable for Result<(), E> {
fn size(&self) -> usize {
1usize + match *self {
match *self {
Ok(_) => 0,
Err(ref e) => e.size(),
}
@@ -75,17 +75,17 @@ impl<E: BinaryConvertable> BinaryConvertable for Result<(), E> {
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
match *self {
Ok(_) => Ok(()),
Ok(_) => Err(BinaryConvertError),
Err(ref e) => Ok(try!(e.to_bytes(buffer, length_stack))),
}
}
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
match buffer[0] {
0 => Ok(Ok(())),
1 => Ok(Err(try!(E::from_bytes(&buffer[1..], length_stack)))),
_ => Err(BinaryConvertError)
}
Ok(Err(try!(E::from_bytes(&buffer, length_stack))))
}
fn from_empty_bytes() -> Result<Self, BinaryConvertError> {
Ok(Ok(()))
}
fn len_params() -> usize {
@@ -104,8 +104,8 @@ impl<R: BinaryConvertable, E: BinaryConvertable> BinaryConvertable for Result<R,
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
match *self {
Ok(ref r) => Ok(try!(r.to_bytes(buffer, length_stack))),
Err(ref e) => Ok(try!(e.to_bytes(buffer, length_stack))),
Ok(ref r) => { buffer[0] = 0; Ok(try!(r.to_bytes(&mut buffer[1..], length_stack))) },
Err(ref e) => { buffer[1] = 1; Ok(try!(e.to_bytes(&mut buffer[1..], length_stack))) },
}
}
@@ -297,29 +297,29 @@ pub fn deserialize_from<T, R>(r: &mut R) -> Result<T, BinaryConvertError>
T::from_bytes(&payload_buffer[..], &mut fake_stack)
},
_ => {
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); };
let mut payload = Vec::new();
try!(r.read_to_end(&mut payload).map_err(|_| BinaryConvertError));
try!(r.read(&mut header_buffer[..]).map_err(|_| BinaryConvertError));
let mut length_stack = VecDeque::<usize>::new();
let stack_len = try!(u64::from_bytes(&payload[0..8], &mut fake_stack)) as usize;
if stack_len > 0 {
for idx in 0..stack_len {
let stack_item = try!(u64::from_bytes(&header_buffer[idx*8..(idx+1)*8], &mut fake_stack));
let stack_item = try!(u64::from_bytes(&payload[8 + idx*8..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)
//try!(r.read(&mut size_buffer).map_err(|_| BinaryConvertError));
let size = try!(u64::from_bytes(&payload[8+stack_len*8..16+stack_len*8], &mut fake_stack)) as usize;
match size {
0 => {
T::from_empty_bytes()
},
_ => {
T::from_bytes(&payload[16+stack_len*8..], &mut length_stack)
}
}
},
}
}
@@ -350,6 +350,12 @@ pub fn serialize_into<T, W>(t: &T, w: &mut W) -> Result<(), BinaryConvertError>
let mut size_buffer = [0u8; 8];
let size = t.size();
if size == 0 {
try!(w.write(&size_buffer).map_err(|_| BinaryConvertError));
try!(w.write(&size_buffer).map_err(|_| BinaryConvertError));
return Ok(());
}
let mut buffer = Vec::with_capacity(size);
unsafe { buffer.set_len(size); }
try!(t.to_bytes(&mut buffer[..], &mut length_stack));
@@ -386,7 +392,8 @@ pub fn serialize<T: BinaryConvertable>(t: &T) -> Result<Vec<u8>, BinaryConvertEr
use std::io::Cursor;
let mut buff = Cursor::new(Vec::new());
try!(serialize_into(t, &mut buff));
Ok(buff.into_inner())
let into_inner = buff.into_inner();
Ok(into_inner)
}
#[macro_export]
@@ -544,7 +551,7 @@ fn deserialize_from_ok() {
fn serialize_into_deserialize_from() {
use std::io::{Cursor, SeekFrom, Seek};
let mut buff = Cursor::new(vec![0u8; 1024]);
let mut buff = Cursor::new(Vec::new());
let mut v = Vec::new();
v.push(Some(5u64));
v.push(None);
@@ -557,3 +564,58 @@ fn serialize_into_deserialize_from() {
let de_v = deserialize_from::<Vec<Option<u64>>, _>(&mut buff).unwrap();
assert_eq!(v, de_v);
}
#[test]
fn serialize_opt_vec() {
use std::io::Cursor;
let mut buff = Cursor::new(Vec::new());
let optional_vec: Option<Vec<u8>> = None;
serialize_into(&optional_vec, &mut buff).unwrap();
assert_eq!(&vec![0u8; 16], buff.get_ref());
}
#[test]
fn serialize_opt_vec_payload() {
use std::io::Cursor;
let optional_vec: Option<Vec<u8>> = None;
let payload = serialize(&optional_vec).unwrap();
assert_eq!(vec![0u8;16], payload);
}
#[test]
fn deserialize_opt_vec() {
use std::io::Cursor;
let mut buff = Cursor::new(vec![0u8; 16]);
let vec = deserialize_from::<Option<Vec<u8>>, _>(&mut buff).unwrap();
assert!(vec.is_none());
}
#[test]
fn deserialize_simple_err() {
use std::io::Cursor;
let mut buff = Cursor::new(vec![0u8; 16]);
let result = deserialize_from::<Result<(), u32>, _>(&mut buff).unwrap();
assert!(result.is_ok());
}
#[test]
fn deserialize_opt_vec_in_out() {
use std::io::{Cursor, SeekFrom, Seek};
let mut buff = Cursor::new(Vec::new());
let optional_vec: Option<Vec<u8>> = None;
serialize_into(&optional_vec, &mut buff).unwrap();
buff.seek(SeekFrom::Start(0)).unwrap();
let vec = deserialize_from::<Option<Vec<u8>>, _>(&mut buff).unwrap();
assert!(vec.is_none());
}

View File

@@ -42,3 +42,17 @@ pub enum EnumWithStruct {
Left,
Right { how_much: u64 },
}
#[derive(Binary)]
pub struct TwoVec {
v1: Vec<u8>,
v2: Vec<u8>,
}
#[test]
fn opt_two_vec() {
let example: Option<TwoVec> = None;
let serialized = ::ipc::binary::serialize(&example).unwrap();
assert_eq!(serialized, vec![0u8; 16]);
}

View File

@@ -30,6 +30,7 @@ pub struct DB<L: Sized> {
pub trait DBWriter {
fn write(&self, data: Vec<u8>) -> Result<(), DBError>;
fn write_slice(&self, data: &[u8]) -> Result<(), DBError>;
}
impl<L: Sized> IpcConfig for DB<L> {}
@@ -44,5 +45,11 @@ impl<L: Sized> DBWriter for DB<L> {
*writes = *writes + data.len() as u64;
Ok(())
}
fn write_slice(&self, data: &[u8]) -> Result<(), DBError> {
let mut writes = self.writes.write().unwrap();
*writes = *writes + data.len() as u64;
Ok(())
}
}