refactored to new serialization

This commit is contained in:
Nikolay Volf 2016-04-22 19:45:09 +03:00
parent 6b1db6a656
commit dcb7546d6d
11 changed files with 192 additions and 381 deletions

View File

@ -36,9 +36,6 @@ use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder; use syntax::ext::build::AstBuilder;
use syntax::ptr::P; use syntax::ptr::P;
use super::typegen;
use std::collections::HashMap;
pub struct Error; pub struct Error;
const RESERVED_MESSAGE_IDS: u16 = 16; const RESERVED_MESSAGE_IDS: u16 = 16;
@ -73,7 +70,7 @@ pub fn expand_ipc_implementation(
fn push_handshake_struct(cx: &ExtCtxt, push: &mut FnMut(Annotatable)) { fn push_handshake_struct(cx: &ExtCtxt, push: &mut FnMut(Annotatable)) {
let handshake_item = quote_item!(cx, let handshake_item = quote_item!(cx,
#[derive(Serialize, Deserialize)] #[derive(Binary)]
pub struct BinHandshake { pub struct BinHandshake {
api_version: String, api_version: String,
protocol_version: String, protocol_version: String,
@ -95,7 +92,6 @@ fn push_invoke_signature_aster(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
implement: &ImplItem, implement: &ImplItem,
signature: &MethodSig, signature: &MethodSig,
replacements: &HashMap<String, P<Ty>>,
push: &mut FnMut(Annotatable), push: &mut FnMut(Annotatable),
) -> Dispatch { ) -> Dispatch {
let inputs = &signature.decl.inputs; let inputs = &signature.decl.inputs;
@ -113,12 +109,11 @@ fn push_invoke_signature_aster(
let arg_ty = &inputs[skip-1].ty; let arg_ty = &inputs[skip-1].ty;
let mut tree = builder.item() let mut tree = builder.item()
.attr().word("derive(Serialize, Deserialize)") .attr().word("derive(Binary)")
.attr().word("allow(non_camel_case_types)") .attr().word("allow(non_camel_case_types)")
.struct_(name_str.as_str()) .struct_(name_str.as_str())
.field(arg_name.as_str()).ty() .field(arg_name.as_str()).ty()
.build(typegen::argument_replacement(builder, replacements, arg_ty) .build(strip_ptr(arg_ty));
.unwrap_or(strip_ptr(arg_ty)));
arg_names.push(arg_name); arg_names.push(arg_name);
arg_tys.push(arg_ty.clone()); arg_tys.push(arg_ty.clone());
@ -126,9 +121,7 @@ fn push_invoke_signature_aster(
let arg_name = format!("{}", field_name(builder, &arg)); let arg_name = format!("{}", field_name(builder, &arg));
let arg_ty = &arg.ty; let arg_ty = &arg.ty;
tree = tree.field(arg_name.as_str()).ty().build( tree = tree.field(arg_name.as_str()).ty().build(strip_ptr(arg_ty));
typegen::argument_replacement(builder, replacements, arg_ty).unwrap_or(strip_ptr(arg_ty))
);
arg_names.push(arg_name); arg_names.push(arg_name);
arg_tys.push(arg_ty.clone()); arg_tys.push(arg_ty.clone());
} }
@ -145,7 +138,7 @@ fn push_invoke_signature_aster(
FunctionRetTy::Ty(ref ty) => { FunctionRetTy::Ty(ref ty) => {
let name_str = format!("{}_output", implement.ident.name.as_str()); let name_str = format!("{}_output", implement.ident.name.as_str());
let tree = builder.item() let tree = builder.item()
.attr().word("derive(Serialize, Deserialize)") .attr().word("derive(Binary)")
.attr().word("allow(non_camel_case_types)") .attr().word("allow(non_camel_case_types)")
.struct_(name_str.as_str()) .struct_(name_str.as_str())
.field(format!("payload")).ty().build(ty.clone()); .field(format!("payload")).ty().build(ty.clone());
@ -184,20 +177,13 @@ fn implement_dispatch_arm_invoke_stmt(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
dispatch: &Dispatch, dispatch: &Dispatch,
replacements: &HashMap<String, P<Ty>>,
) -> ast::Stmt ) -> ast::Stmt
{ {
let function_name = builder.id(dispatch.function_name.as_str()); let function_name = builder.id(dispatch.function_name.as_str());
let input_args_exprs = dispatch.input_arg_names.iter().enumerate().map(|(arg_index, arg_name)| { let input_args_exprs = dispatch.input_arg_names.iter().enumerate().map(|(arg_index, arg_name)| {
let arg_ident = builder.id(arg_name); let arg_ident = builder.id(arg_name);
let expr = if typegen::argument_replacement(builder, replacements, &dispatch.input_arg_tys[arg_index]).is_some() { let expr = quote_expr!(cx, input. $arg_ident);
quote_expr!(cx, input. $arg_ident .into())
}
else {
quote_expr!(cx, input. $arg_ident)
};
if has_ptr(&dispatch.input_arg_tys[arg_index]) { quote_expr!(cx, & $expr) } if has_ptr(&dispatch.input_arg_tys[arg_index]) { quote_expr!(cx, & $expr) }
else { expr } else { expr }
}).collect::<Vec<P<ast::Expr>>>(); }).collect::<Vec<P<ast::Expr>>>();
@ -211,9 +197,9 @@ fn implement_dispatch_arm_invoke_stmt(
let mut tt = ::std::vec::Vec::new(); let mut tt = ::std::vec::Vec::new();
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("ipc"), ::syntax::parse::token::ModName)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serde"), ::syntax::parse::token::ModName))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("binary"), ::syntax::parse::token::ModName)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"), ::syntax::parse::token::Plain))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
@ -229,13 +215,6 @@ fn implement_dispatch_arm_invoke_stmt(
} }
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("SizeLimit"), ::syntax::parse::token::ModName)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Infinite"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"), ::syntax::parse::token::Plain))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"), ::syntax::parse::token::Plain)));
@ -251,16 +230,15 @@ fn implement_dispatch_arm_invoke(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
dispatch: &Dispatch, dispatch: &Dispatch,
buffer: bool, buffer: bool,
replacements: &HashMap<String, P<Ty>>,
) -> P<ast::Expr> ) -> P<ast::Expr>
{ {
let deserialize_expr = if buffer { let deserialize_expr = if buffer {
quote_expr!(cx, ::bincode::serde::deserialize(buf).expect("ipc deserialization error, aborting")) quote_expr!(cx, ::ipc::binary::deserialize(buf).expect("ipc deserialization error, aborting"))
} else { } else {
quote_expr!(cx, ::bincode::serde::deserialize_from(r, ::bincode::SizeLimit::Infinite).expect("ipc deserialization error, aborting")) quote_expr!(cx, ::ipc::binary::deserialize_from(r).expect("ipc deserialization error, aborting"))
}; };
let invoke_serialize_stmt = implement_dispatch_arm_invoke_stmt(cx, builder, dispatch, replacements); let invoke_serialize_stmt = implement_dispatch_arm_invoke_stmt(cx, builder, dispatch);
dispatch.input_type_name.as_ref().map(|val| { dispatch.input_type_name.as_ref().map(|val| {
let input_type_id = builder.id(val.clone().as_str()); let input_type_id = builder.id(val.clone().as_str());
quote_expr!(cx, { quote_expr!(cx, {
@ -277,11 +255,10 @@ fn implement_dispatch_arm(
index: u32, index: u32,
dispatch: &Dispatch, dispatch: &Dispatch,
buffer: bool, buffer: bool,
replacements: &HashMap<String, P<Ty>>,
) -> ast::Arm ) -> ast::Arm
{ {
let index_ident = builder.id(format!("{}", index + (RESERVED_MESSAGE_IDS as u32)).as_str()); let index_ident = builder.id(format!("{}", index + (RESERVED_MESSAGE_IDS as u32)).as_str());
let invoke_expr = implement_dispatch_arm_invoke(cx, builder, dispatch, buffer, replacements); let invoke_expr = implement_dispatch_arm_invoke(cx, builder, dispatch, buffer);
quote_arm!(cx, $index_ident => { $invoke_expr } ) quote_arm!(cx, $index_ident => { $invoke_expr } )
} }
@ -290,12 +267,11 @@ fn implement_dispatch_arms(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
dispatches: &[Dispatch], dispatches: &[Dispatch],
buffer: bool, buffer: bool,
replacements: &HashMap<String, P<Ty>>,
) -> Vec<ast::Arm> ) -> Vec<ast::Arm>
{ {
let mut index = -1; let mut index = -1;
dispatches.iter() dispatches.iter()
.map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch, buffer, replacements) }).collect() .map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch, buffer) }).collect()
} }
pub fn strip_ptr(ty: &P<ast::Ty>) -> P<ast::Ty> { pub fn strip_ptr(ty: &P<ast::Ty>) -> P<ast::Ty> {
@ -349,10 +325,10 @@ fn implement_client_method_body(
.ty().ref_() .ty().ref_()
.lifetime("'a") .lifetime("'a")
.ty() .ty()
.build(typegen::argument_replacement(builder, &interface_map.replacements, &static_ty).unwrap_or(static_ty.clone())); .build(static_ty.clone());
let mut tree = builder.item() let mut tree = builder.item()
.attr().word("derive(Serialize)") .attr().word("derive(Binary)")
.struct_("Request") .struct_("Request")
.generics() .generics()
.lifetime_name("'a") .lifetime_name("'a")
@ -368,7 +344,7 @@ fn implement_client_method_body(
.ty().ref_() .ty().ref_()
.lifetime("'a") .lifetime("'a")
.ty() .ty()
.build(typegen::argument_replacement(builder, &interface_map.replacements, &static_ty).unwrap_or(static_ty)); .build(static_ty);
tree = tree.field(arg_name).ty().build(arg_ty); tree = tree.field(arg_name).ty().build(arg_ty);
} }
@ -395,28 +371,12 @@ fn implement_client_method_body(
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Request"), ::syntax::parse::token::Plain))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Request"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
for (idx, arg) in dispatch.input_arg_names.iter().enumerate() { for arg in dispatch.input_arg_names.iter() {
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()), ::syntax::parse::token::Plain))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
let arg_ty = &dispatch.input_arg_tys[idx];
let replacement = typegen::argument_replacement(builder, &interface_map.replacements, arg_ty);
if let Some(ref replacement_ty) = replacement {
let replacor_ident = ::syntax::print::pprust::ty_to_string(replacement_ty);
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(&replacor_ident), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("from"), ::syntax::parse::token::Plain)));
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
}
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()), ::syntax::parse::token::Plain))); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()), ::syntax::parse::token::Plain)));
if replacement.is_some() {
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
}
tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma)); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma));
} }
@ -432,7 +392,7 @@ fn implement_client_method_body(
quote_stmt!(cx, let mut socket = socket_ref.deref_mut())); quote_stmt!(cx, let mut socket = socket_ref.deref_mut()));
request_serialization_statements.push( request_serialization_statements.push(
quote_stmt!(cx, let serialized_payload = ::bincode::serde::serialize(&payload, ::bincode::SizeLimit::Infinite).unwrap())); quote_stmt!(cx, let serialized_payload = ::ipc::binary::serialize(&payload).unwrap()));
request_serialization_statements.push( request_serialization_statements.push(
quote_stmt!(cx, ::ipc::invoke($index_ident, &Some(serialized_payload), &mut socket))); quote_stmt!(cx, ::ipc::invoke($index_ident, &Some(serialized_payload), &mut socket)));
@ -453,7 +413,7 @@ fn implement_client_method_body(
if let Some(ref return_ty) = dispatch.return_type_ty { if let Some(ref return_ty) = dispatch.return_type_ty {
let return_expr = quote_expr!(cx, let return_expr = quote_expr!(cx,
::bincode::serde::deserialize_from::<_, $return_ty>(&mut socket, ::bincode::SizeLimit::Infinite).unwrap() ::ipc::binary::deserialize_from::<$return_ty, _>(&mut socket).unwrap()
); );
quote_expr!(cx, { quote_expr!(cx, {
$request $request
@ -632,7 +592,7 @@ fn push_client_implementation(
let mut socket = socket_ref.deref_mut(); let mut socket = socket_ref.deref_mut();
::ipc::invoke( ::ipc::invoke(
0, 0,
&Some(::bincode::serde::serialize(&payload, ::bincode::SizeLimit::Infinite).unwrap()), &Some(::ipc::binary::serialize(&payload).unwrap()),
&mut socket); &mut socket);
let mut result = vec![0u8; 1]; let mut result = vec![0u8; 1];
@ -696,18 +656,18 @@ fn implement_handshake_arm(
) -> (ast::Arm, ast::Arm) ) -> (ast::Arm, ast::Arm)
{ {
let handshake_deserialize = quote_stmt!(&cx, let handshake_deserialize = quote_stmt!(&cx,
let handshake_payload = ::bincode::serde::deserialize_from::<_, BinHandshake>(r, ::bincode::SizeLimit::Infinite).unwrap(); let handshake_payload = ::ipc::binary::deserialize_from::<BinHandshake, _>(r).unwrap();
); );
let handshake_deserialize_buf = quote_stmt!(&cx, let handshake_deserialize_buf = quote_stmt!(&cx,
let handshake_payload = ::bincode::serde::deserialize::<BinHandshake>(buf).unwrap(); let handshake_payload = ::ipc::binary::deserialize::<BinHandshake>(buf).unwrap();
); );
let handshake_serialize = quote_expr!(&cx, let handshake_serialize = quote_expr!(&cx,
::bincode::serde::serialize::<bool>(&Self::handshake(&::ipc::Handshake { ::ipc::binary::serialize::<bool>(&Self::handshake(&::ipc::Handshake {
api_version: ::semver::Version::parse(&handshake_payload.api_version).unwrap(), api_version: ::semver::Version::parse(&handshake_payload.api_version).unwrap(),
protocol_version: ::semver::Version::parse(&handshake_payload.protocol_version).unwrap(), protocol_version: ::semver::Version::parse(&handshake_payload.protocol_version).unwrap(),
}), ::bincode::SizeLimit::Infinite).unwrap() })).unwrap()
); );
( (
@ -722,22 +682,11 @@ fn implement_handshake_arm(
) )
} }
fn collect_tys(items: &[&MethodSig]) -> Vec<P<Ty>> {
let mut result = Vec::new();
for signature in items {
result.extend(signature.decl.inputs.iter().map(|input_arg| input_arg.ty.clone()));
if let FunctionRetTy::Ty(ref ty) = signature.decl.output {
result.push(ty.clone())
};
}
result
}
struct InterfaceMap { struct InterfaceMap {
pub original_item: Item, pub original_item: Item,
pub item: P<ast::Item>, pub item: P<ast::Item>,
pub dispatches: Vec<Dispatch>, pub dispatches: Vec<Dispatch>,
pub replacements: HashMap<String, P<Ty>>,
pub generics: Generics, pub generics: Generics,
pub impl_trait: Option<TraitRef>, pub impl_trait: Option<TraitRef>,
pub ident_map: IdentMap, pub ident_map: IdentMap,
@ -796,20 +745,12 @@ fn implement_interface(
} }
} }
let all_tys = collect_tys(
&method_signatures
.iter()
.map(|&(_, signature)| signature)
.collect::<Vec<&MethodSig>>());
let replacements = typegen::match_unknown_tys(cx, builder, &all_tys, push);
let dispatch_table = method_signatures.iter().map(|&(impl_item, signature)| let dispatch_table = method_signatures.iter().map(|&(impl_item, signature)|
push_invoke_signature_aster(builder, impl_item, signature, &replacements, push)) push_invoke_signature_aster(builder, impl_item, signature, push))
.collect::<Vec<Dispatch>>(); .collect::<Vec<Dispatch>>();
let dispatch_arms = implement_dispatch_arms(cx, builder, &dispatch_table, false, &replacements); let dispatch_arms = implement_dispatch_arms(cx, builder, &dispatch_table, false);
let dispatch_arms_buffered = implement_dispatch_arms(cx, builder, &dispatch_table, true, &replacements); let dispatch_arms_buffered = implement_dispatch_arms(cx, builder, &dispatch_table, true);
let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx); let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
@ -852,7 +793,6 @@ fn implement_interface(
original_item: item.clone(), original_item: item.clone(),
item: ipc_item, item: ipc_item,
dispatches: dispatch_table, dispatches: dispatch_table,
replacements: replacements,
generics: generics.clone(), generics: generics.clone(),
impl_trait: impl_trait.clone(), impl_trait: impl_trait.clone(),
}) })

View File

@ -16,4 +16,3 @@
mod codegen; mod codegen;
mod serialization; mod serialization;
pub mod typegen;

View File

@ -166,18 +166,21 @@ fn binary_expr_struct(
let size_exprs: Vec<P<ast::Expr>> = fields.iter().enumerate().map(|(index, field)| { let size_exprs: Vec<P<ast::Expr>> = fields.iter().enumerate().map(|(index, field)| {
let field_type_ident = builder.id( let field_type_ident = builder.id(
&::syntax::print::pprust::ty_to_string( &::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)));
&codegen::strip_ptr(&field.ty)));
let field_type_ident_qualified = builder.id(
&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)).replace("<", "::<"));
let index_ident = builder.id(format!("__field{}", index)); let index_ident = builder.id(format!("__field{}", index));
value_ident.and_then(|x| { value_ident.and_then(|x| {
let field_id = builder.id(field.ident.unwrap()); let field_id = builder.id(field.ident.unwrap());
Some(quote_expr!(cx, Some(quote_expr!(cx,
match $field_type_ident::len_params() { match $field_type_ident_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(), 0 => mem::size_of::<$field_type_ident>(),
_ => $x. $field_id .size() _ => $x. $field_id .size()
})) }))
}) })
.unwrap_or_else(|| quote_expr!(cx, match $field_type_ident::len_params() { .unwrap_or_else(|| quote_expr!(cx, match $field_type_ident_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(), 0 => mem::size_of::<$field_type_ident>(),
_ => $index_ident .size() _ => $index_ident .size()
})) }))
@ -199,8 +202,10 @@ fn binary_expr_struct(
map_stmts.push(quote_stmt!(cx, let mut total = 0usize;).unwrap()); map_stmts.push(quote_stmt!(cx, let mut total = 0usize;).unwrap());
for (index, field) in fields.iter().enumerate() { for (index, field) in fields.iter().enumerate() {
let field_type_ident = builder.id( let field_type_ident = builder.id(
&::syntax::print::pprust::ty_to_string( &::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)));
&codegen::strip_ptr(&field.ty)));
let field_type_ident_qualified = builder.id(
&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)).replace("<", "::<"));
let member_expr = match value_ident { let member_expr = match value_ident {
Some(x) => { Some(x) => {
@ -213,7 +218,7 @@ fn binary_expr_struct(
} }
}; };
write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident::len_params() { write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(), 0 => mem::size_of::<$field_type_ident>(),
_ => { let size = $member_expr .size(); length_stack.push_back(size); size } _ => { let size = $member_expr .size(); length_stack.push_back(size); size }
}).unwrap()); }).unwrap());
@ -225,7 +230,7 @@ fn binary_expr_struct(
let field_index = builder.id(&format!("{}", index)); let field_index = builder.id(&format!("{}", index));
map_stmts.push(quote_stmt!(cx, map[$field_index] = total;).unwrap()); map_stmts.push(quote_stmt!(cx, map[$field_index] = total;).unwrap());
map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident::len_params() { map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident_qualified::len_params() {
0 => mem::size_of::<$field_type_ident>(), 0 => mem::size_of::<$field_type_ident>(),
_ => length_stack.pop_front().unwrap() _ => length_stack.pop_front().unwrap()
}).unwrap()); }).unwrap());
@ -371,7 +376,7 @@ fn fields_sequence(
tt.push(Token( tt.push(Token(
_sp, _sp,
token::Ident( token::Ident(
ext_cx.ident_of(&::syntax::print::pprust::ty_to_string(&field.ty)), ext_cx.ident_of(&::syntax::print::pprust::ty_to_string(&field.ty).replace("<", "::<")),
token::Plain))); token::Plain)));
tt.push(Token(_sp, token::ModSep)); tt.push(Token(_sp, token::ModSep));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("from_bytes"), token::Plain))); tt.push(Token(_sp, token::Ident(ext_cx.ident_of("from_bytes"), token::Plain)));
@ -445,7 +450,7 @@ fn named_fields_sequence(
tt.push(Token( tt.push(Token(
_sp, _sp,
token::Ident( token::Ident(
ext_cx.ident_of(&::syntax::print::pprust::ty_to_string(&field.ty)), ext_cx.ident_of(&::syntax::print::pprust::ty_to_string(&field.ty).replace("<", "::<")),
token::Plain))); token::Plain)));
tt.push(Token(_sp, token::ModSep)); tt.push(Token(_sp, token::ModSep));
tt.push(Token(_sp, token::Ident(ext_cx.ident_of("from_bytes"), token::Plain))); tt.push(Token(_sp, token::Ident(ext_cx.ident_of("from_bytes"), token::Plain)));

View File

@ -1,247 +0,0 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use aster;
use syntax::ast::{
Ty,
TyKind,
Path,
DUMMY_NODE_ID,
};
use syntax::ast;
use syntax::ext::base::{Annotatable, ExtCtxt};
use syntax::ext::build::AstBuilder;
use syntax::ptr::P;
use std::collections::{HashMap, HashSet};
use std::ops::Deref;
fn is_new_entry(path: &Path) -> Option<String> {
let known = {
if path.segments.len() > 1 {
false
} else {
let ident = format!("{}", path.segments[0].identifier.name.as_str());
ident == "u8" ||
ident == "i8" ||
ident == "u16" ||
ident == "i16" ||
ident == "u32" ||
ident == "u64" ||
ident == "usize" ||
ident == "i32" ||
ident == "i64" ||
ident == "String" ||
ident == "bool" ||
ident == "H256" ||
ident == "U256" ||
ident == "H2048" ||
ident == "Address" ||
ident == "Bytes"
}
};
if known { None }
else { Some(::syntax::print::pprust::path_to_string(path)) }
}
pub fn argument_replacement(
builder: &aster::AstBuilder,
replacements: &HashMap<String, P<Ty>>,
ty: &P<Ty>,
) -> Option<P<Ty>> {
match ty.node {
TyKind::Vec(ref nested_ty) => {
argument_replacement(builder, replacements, nested_ty).and_then(|replaced_with| {
let mut inplace_ty = nested_ty.deref().clone();
inplace_ty.node = TyKind::Vec(replaced_with);
inplace_ty.id = DUMMY_NODE_ID;
Some(P(inplace_ty))
})
},
TyKind::FixedLengthVec(ref nested_ty, ref len_expr) => {
argument_replacement(builder, replacements, nested_ty).and_then(|replaced_with| {
let mut inplace_ty = nested_ty.deref().clone();
inplace_ty.node = TyKind::FixedLengthVec(replaced_with, len_expr.clone());
inplace_ty.id = DUMMY_NODE_ID;
Some(P(inplace_ty))
})
},
TyKind::Path(_, ref path) => {
if path.segments.len() > 0 && path.segments[0].identifier.name.as_str() == "Option" ||
path.segments[0].identifier.name.as_str() == "Result" {
let nested_ty = &path.segments[0].parameters.types()[0];
argument_replacement(builder, replacements, nested_ty).and_then(|replaced_with| {
let mut inplace_path = path.clone();
match inplace_path.segments[0].parameters {
ast::PathParameters::AngleBracketed(ref mut data) => {
data.types = data.types.map(|_| replaced_with.clone());
},
_ => {}
}
let mut inplace_ty = nested_ty.deref().deref().clone();
inplace_ty.node = TyKind::Path(None, inplace_path);
inplace_ty.id = DUMMY_NODE_ID;
Some(P(inplace_ty))
})
}
else {
replacements.get(&::syntax::print::pprust::path_to_string(path)).and_then(|replaced_with| {
Some(replaced_with.clone())
})
}
}
_ => { None }
}
}
pub fn push_bin_box(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
ty: &Ty,
bbox_name: &str,
push: &mut FnMut(Annotatable),
) {
let ident = builder.id(bbox_name);
let bin_box_struct = quote_item!(cx,
struct $ident ($ty);
).unwrap();
push(Annotatable::Item(bin_box_struct));
push(Annotatable::Item(quote_item!(cx,
impl From<$ty> for $ident {
fn from(val: $ty) -> $ident {
$ident(val)
}
}).unwrap()));
push(Annotatable::Item(quote_item!(cx,
impl Into<$ty> for $ident {
fn into(self) -> $ty {
let $ident(val) = self;
val
}
}).unwrap()));
let serialize_impl = quote_item!(cx,
impl ::serde::ser::Serialize for $ident {
fn serialize<__S>(&self, serializer: &mut __S) -> ::std::result::Result<(), __S::Error>
where __S: ::serde::ser::Serializer
{
let &$ident(ref val) = self;
serializer.serialize_bytes(val.as_slice())
}
}).unwrap();
let ident_expr = builder.id(::syntax::print::pprust::ty_to_string(ty));
let deserialize_impl = quote_item!(cx,
impl ::serde::de::Deserialize for $ident {
fn deserialize<__D>(deserializer: &mut __D) -> ::std::result::Result<$ident, __D::Error>
where __D: ::serde::de::Deserializer
{
struct __Visitor<__D: ::serde::de::Deserializer>(::std::marker::PhantomData<__D>);
impl <__D: ::serde::de::Deserializer> ::serde::de::Visitor for __Visitor<__D> {
type Value = $ident;
#[inline]
fn visit_seq<__V>(&mut self, mut visitor: __V) -> ::std::result::Result<$ident, __V::Error>
where __V: ::serde::de::SeqVisitor
{
let raw_bytes: Vec<u8> = try!(visitor.visit()).unwrap_or_else(|| Vec::new());
let inner = $ident_expr ::from_bytes(&raw_bytes).unwrap();
Ok($ident (inner))
}
}
deserializer.deserialize_bytes(__Visitor::<__D>(::std::marker::PhantomData))
}
}).unwrap();
push(Annotatable::Item(serialize_impl));
push(Annotatable::Item(deserialize_impl));
}
pub fn match_unknown_tys(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
tys: &[P<Ty>],
push: &mut FnMut(Annotatable),
) -> HashMap<String, P<Ty>>
{
let mut hash_map = HashMap::new();
let mut fringe = Vec::new();
fringe.extend(tys);
let mut stop_list = HashSet::new();
let mut index = 0;
loop {
if fringe.len() == 0 { break; }
let drained = fringe.drain(..1).collect::<Vec<&P<Ty>>>();
let ty = drained[0];
stop_list.insert(ty);
match ty.node {
TyKind::Vec(ref nested_ty) => {
if !stop_list.contains(nested_ty) {
fringe.push(nested_ty);
}
},
TyKind::FixedLengthVec(ref nested_ty, _) => {
if !stop_list.contains(nested_ty) {
fringe.push(nested_ty);
}
},
TyKind::Rptr(_, ref nested_ty) => {
if !stop_list.contains(&nested_ty.ty) {
fringe.push(&nested_ty.ty);
}
},
TyKind::Path(_, ref path) => {
if path.segments.len() > 0 && {
let first_segment = path.segments[0].identifier.name.as_str();
first_segment == "Option" || first_segment == "Result" || first_segment == "Vec"
}
{
let extra_type = &path.segments[0].parameters.types()[0];
if !stop_list.contains(extra_type) {
fringe.push(extra_type);
}
continue;
}
match is_new_entry(path) {
Some(old_path) => {
if hash_map.get(&old_path).is_some() {
continue;
}
let bin_box_name = format!("BinBox{}", index);
push_bin_box(cx, builder, &ty, &bin_box_name, push);
hash_map.insert(old_path, builder.ty().id(&bin_box_name));
index = index + 1;
},
None => {}
}
},
_ => { }
}
}
hash_map
}

View File

@ -63,6 +63,63 @@ impl<T> BinaryConvertable for Option<T> where T: BinaryConvertable {
} }
} }
impl<E: BinaryConvertable> BinaryConvertable for Result<(), E> {
fn size(&self) -> usize {
1usize + match *self {
Ok(ref r) => 0,
Err(ref e) => e.size(),
}
}
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
match *self {
Ok(ref r) => Ok(()),
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)
}
}
fn len_params() -> usize {
1
}
}
impl<R: BinaryConvertable, E: BinaryConvertable> BinaryConvertable for Result<R, E> {
fn size(&self) -> usize {
1usize + match *self {
Ok(ref r) => r.size(),
Err(ref e) => e.size(),
}
}
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))),
}
}
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
match buffer[0] {
0 => Ok(Ok(try!(R::from_bytes(&buffer[1..], length_stack)))),
1 => Ok(Err(try!(E::from_bytes(&buffer[1..], length_stack)))),
_ => Err(BinaryConvertError)
}
}
fn len_params() -> usize {
1
}
}
impl<T> BinaryConvertable for Vec<T> where T: BinaryConvertable { impl<T> BinaryConvertable for Vec<T> where T: BinaryConvertable {
fn size(&self) -> usize { fn size(&self) -> usize {
match T::len_params() { match T::len_params() {
@ -128,6 +185,55 @@ impl<T> BinaryConvertable for Vec<T> where T: BinaryConvertable {
} }
} }
impl BinaryConvertable for String {
fn size(&self) -> usize {
self.as_bytes().len()
}
fn from_empty_bytes() -> Result<Self, BinaryConvertError> {
Ok(String::new())
}
fn to_bytes(&self, buffer: &mut [u8], _length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
buffer[..].clone_from_slice(self.as_bytes());
Ok(())
}
fn from_bytes(buffer: &[u8], _length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
Ok(::std::str::from_utf8(buffer).unwrap().to_owned())
}
fn len_params() -> usize {
1
}
}
impl BinaryConvertable for Vec<u8> {
fn size(&self) -> usize {
self.len()
}
fn from_empty_bytes() -> Result<Self, BinaryConvertError> {
Ok(Vec::new())
}
fn to_bytes(&self, buffer: &mut [u8], _length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
buffer[..].clone_from_slice(&self[..]);
Ok(())
}
fn from_bytes(buffer: &[u8], _length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
let mut res = Self::with_capacity(buffer.len());
unsafe { res.set_len(buffer.len()) }
res[..].clone_from_slice(&buffer[..]);
Ok(res)
}
fn len_params() -> usize {
1
}
}
pub fn deserialize_from<T, R>(r: &mut R) -> Result<T, BinaryConvertError> pub fn deserialize_from<T, R>(r: &mut R) -> Result<T, BinaryConvertError>
where R: ::std::io::Read, where R: ::std::io::Read,
T: BinaryConvertable T: BinaryConvertable
@ -158,6 +264,12 @@ pub fn deserialize_from<T, R>(r: &mut R) -> Result<T, BinaryConvertError>
T::from_bytes(&data[..], &mut length_stack) T::from_bytes(&data[..], &mut length_stack)
} }
pub fn deserialize<T: BinaryConvertable>(buffer: &[u8]) -> Result<T, BinaryConvertError> {
use std::io::Cursor;
let mut buff = Cursor::new(buffer);
deserialize_from::<T, _>(&mut buff)
}
pub fn serialize_into<T, W>(t: &T, w: &mut W) -> Result<(), BinaryConvertError> pub fn serialize_into<T, W>(t: &T, w: &mut W) -> Result<(), BinaryConvertError>
where W: ::std::io::Write, where W: ::std::io::Write,
T: BinaryConvertable T: BinaryConvertable
@ -197,6 +309,13 @@ pub fn serialize_into<T, W>(t: &T, w: &mut W) -> Result<(), BinaryConvertError>
Ok(()) Ok(())
} }
pub fn serialize<T: BinaryConvertable>(t: &T) -> Result<Vec<u8>, BinaryConvertError> {
use std::io::Cursor;
let mut buff = Cursor::new(Vec::new());
try!(serialize_into(t, &mut buff));
Ok(buff.into_inner())
}
macro_rules! binary_fixed_size { macro_rules! binary_fixed_size {
($target_ty: ident) => { ($target_ty: ident) => {
impl BinaryConvertable for $target_ty { impl BinaryConvertable for $target_ty {
@ -226,6 +345,7 @@ macro_rules! binary_fixed_size {
binary_fixed_size!(u64); binary_fixed_size!(u64);
binary_fixed_size!(u32); binary_fixed_size!(u32);
binary_fixed_size!(i32);
binary_fixed_size!(bool); binary_fixed_size!(bool);
#[test] #[test]

View File

@ -38,7 +38,7 @@ pub fn main() {
let src = Path::new(&out_dir).join("nested_ipc.rs"); let src = Path::new(&out_dir).join("nested_ipc.rs");
let dst = Path::new(&out_dir).join("nested_cg.rs"); let dst = Path::new(&out_dir).join("nested_cg.rs");
let mut registry = syntex::Registry::new(); let mut registry = syntex::Registry::new();
serde_codegen::register(&mut registry); codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap(); registry.expand("", &src, &dst).unwrap();
} }
@ -56,7 +56,7 @@ pub fn main() {
let src = Path::new(&out_dir).join("service_ipc.rs"); let src = Path::new(&out_dir).join("service_ipc.rs");
let dst = Path::new(&out_dir).join("service_cg.rs"); let dst = Path::new(&out_dir).join("service_cg.rs");
let mut registry = syntex::Registry::new(); let mut registry = syntex::Registry::new();
serde_codegen::register(&mut registry); codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap(); registry.expand("", &src, &dst).unwrap();
} }

View File

@ -41,12 +41,20 @@ mod tests {
#[test] #[test]
fn call_service_handshake() { fn call_service_handshake() {
let mut socket = TestSocket::new_ready(vec![0, 0, let mut socket = TestSocket::new_ready(vec![0, 0,
// protocol version // part count = 3
0, 0, 0, 0, 0, 0, 0, 5, b'1', b'.', b'0', b'.', b'0', 0, 0, 0, 0, 0, 0, 0, 3,
// api version // part sizes
0, 0, 0, 0, 0, 0, 0, 5, b'1', b'.', b'0', b'.', b'0', 0, 0, 0, 0, 0, 0, 0, 5,
// reserved 0, 0, 0, 0, 0, 0, 0, 5,
0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 64,
// total payload length
0, 0, 0, 0, 0, 0, 0, 70,
// protocol version
b'1', b'.', b'0', b'.', b'0',
// api version
b'1', b'.', b'0', b'.', b'0',
// reserved
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

View File

@ -14,4 +14,5 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/nested_cg.rs")); include!(concat!(env!("OUT_DIR"), "/nested_cg.rs"));

View File

@ -17,6 +17,10 @@
use std::sync::RwLock; use std::sync::RwLock;
use std::ops::*; use std::ops::*;
use ipc::IpcConfig; use ipc::IpcConfig;
use ipc::BinaryConvertable;
use std::mem;
use ipc::binary::BinaryConvertError;
use std::collections::VecDeque;
pub struct DB<L: Sized> { pub struct DB<L: Sized> {
pub writes: RwLock<u64>, pub writes: RwLock<u64>,
@ -30,7 +34,7 @@ pub trait DBWriter {
impl<L: Sized> IpcConfig for DB<L> {} impl<L: Sized> IpcConfig for DB<L> {}
#[derive(Serialize, Deserialize)] #[derive(Binary)]
pub enum DBError { Write, Read } pub enum DBError { Write, Read }
#[derive(Ipc)] #[derive(Ipc)]

View File

@ -14,4 +14,5 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/service_cg.rs")); include!(concat!(env!("OUT_DIR"), "/service_cg.rs"));

View File

@ -16,40 +16,20 @@
use std::sync::RwLock; use std::sync::RwLock;
use std::ops::*; use std::ops::*;
use std::convert::*;
use ipc::IpcConfig; use ipc::IpcConfig;
use util::bytes::{FromRawBytes, BytesConvertable, FromBytesError}; use std::mem;
use ipc::binary::BinaryConvertError;
use std::collections::VecDeque;
pub struct Service { pub struct Service {
pub commits: RwLock<usize>, pub commits: RwLock<usize>,
pub rollbacks: RwLock<usize>, pub rollbacks: RwLock<usize>,
} }
#[derive(Binary)]
pub struct CustomData { pub struct CustomData {
pub a: usize, pub a: u64,
pub b: usize, pub b: u64,
}
impl FromRawBytes for CustomData {
fn from_bytes(bytes: &[u8]) -> Result<CustomData, FromBytesError> {
Ok(CustomData {
a: bytes[0] as usize * 256 + bytes[1] as usize,
b: bytes[2] as usize * 256 + bytes[3] as usize
})
}
}
impl BytesConvertable for CustomData {
fn bytes(&self) -> &[u8] {
let ip: *const CustomData = self;
let ptr: *const u8 = ip as *const _;
unsafe {
::std::slice::from_raw_parts(
ptr,
::std::mem::size_of::<CustomData>()
)
}
}
} }
#[derive(Ipc)] #[derive(Ipc)]
@ -69,8 +49,8 @@ impl Service {
let mut clock = self.commits.write().unwrap(); let mut clock = self.commits.write().unwrap();
let mut rlock = self.commits.write().unwrap(); let mut rlock = self.commits.write().unwrap();
*clock = data.a; *clock = data.a as usize;
*rlock = data.b; *rlock = data.b as usize;
true true
} }