Merge pull request #998 from ethcore/ipc-new-serialization

IPC with new serialization
This commit is contained in:
Arkadiy Paronyan 2016-04-26 15:52:38 +02:00
commit 3865e4cdba
18 changed files with 344 additions and 484 deletions

1
Cargo.lock generated
View File

@ -28,7 +28,6 @@ dependencies = [
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -9,7 +9,6 @@ build = "build.rs"
[build-dependencies] [build-dependencies]
rustc_version = "0.1" rustc_version = "0.1"
syntex = "*" syntex = "*"
serde_codegen = "0.7.0"
"ethcore-ipc-codegen" = { path = "ipc/codegen" } "ethcore-ipc-codegen" = { path = "ipc/codegen" }
[dependencies] [dependencies]

View File

@ -17,7 +17,6 @@
extern crate rustc_version; extern crate rustc_version;
extern crate syntex; extern crate syntex;
extern crate ethcore_ipc_codegen as codegen; extern crate ethcore_ipc_codegen as codegen;
extern crate serde_codegen;
use std::env; use std::env;
use std::path::Path; use std::path::Path;
@ -39,12 +38,12 @@ fn main() {
registry.expand("", &src, &dst).unwrap(); registry.expand("", &src, &dst).unwrap();
} }
// serde pass // serialization pass
{ {
let src = Path::new(&out_dir).join("hypervisor_service_ipc.rs"); let src = Path::new(&out_dir).join("hypervisor_service_ipc.rs");
let dst = Path::new(&out_dir).join("hypervisor_service_cg.rs"); let dst = Path::new(&out_dir).join("hypervisor_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

@ -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;
@ -55,14 +52,14 @@ pub fn expand_ipc_implementation(
_ => { _ => {
cx.span_err(meta_item.span, "`#[derive(Ipc)]` may only be applied to struct implementations"); cx.span_err(meta_item.span, "`#[derive(Ipc)]` may only be applied to struct implementations");
return; return;
} },
}; };
let builder = aster::AstBuilder::new().span(span); let builder = aster::AstBuilder::new().span(span);
let interface_map = match implement_interface(cx, &builder, &item, push) { let interface_map = match implement_interface(cx, &builder, &item, push) {
Ok(interface_map) => interface_map, Ok(interface_map) => interface_map,
Err(Error) => { return; } Err(Error) => { return; },
}; };
push_client(cx, &builder, &interface_map, push); push_client(cx, &builder, &interface_map, push);
@ -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,
@ -784,7 +733,7 @@ fn implement_interface(
item.span, item.span,
"`#[derive(Ipc)]` may only be applied to item implementations"); "`#[derive(Ipc)]` may only be applied to item implementations");
return Err(Error); return Err(Error);
} },
}; };
let impl_generics = builder.from_generics(generics.clone()).build(); let impl_generics = builder.from_generics(generics.clone()).build();
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
@ -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

@ -155,6 +155,16 @@ struct BinaryExpressions {
pub read: P<ast::Expr>, pub read: P<ast::Expr>,
} }
fn replace_qualified(s: &str) -> String {
if let Some(pos) = s.find("<") {
let mut source = s.to_owned();
source.insert(pos, ':');
source.insert(pos, ':');
source
}
else { s.to_owned() }
}
fn binary_expr_struct( fn binary_expr_struct(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
@ -166,18 +176,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(
replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))));
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 +212,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(
replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))));
let member_expr = match value_ident { let member_expr = match value_ident {
Some(x) => { Some(x) => {
@ -213,7 +228,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 +240,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 +386,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(&replace_qualified(&::syntax::print::pprust::ty_to_string(&field.ty))),
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 +460,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(&replace_qualified(&::syntax::print::pprust::ty_to_string(&field.ty))),
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

@ -17,6 +17,7 @@
//! Binary representation of types //! Binary representation of types
use util::bytes::Populatable; use util::bytes::Populatable;
use util::numbers::{U256, H256, H2048, Address};
use std::mem; use std::mem;
use std::collections::VecDeque; use std::collections::VecDeque;
@ -63,6 +64,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(_) => 0,
Err(ref e) => e.size(),
}
}
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
match *self {
Ok(_) => 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,73 +186,183 @@ 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<T> BinaryConvertable for ::std::cell::RefCell<T> where T: BinaryConvertable {
fn size(&self) -> usize {
self.borrow().size()
}
fn from_empty_bytes() -> Result<Self, BinaryConvertError> {
Ok(::std::cell::RefCell::new(try!(T::from_empty_bytes())))
}
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
Ok(::std::cell::RefCell::new(try!(T::from_bytes(buffer, length_stack))))
}
fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque<usize>) -> Result<(), BinaryConvertError> {
try!(self.borrow().to_bytes(buffer, length_stack));
Ok(())
}
fn len_params() -> usize {
T::len_params()
}
}
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
{ {
let mut fake_stack = VecDeque::new(); 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)); match T::len_params() {
for idx in 0..stack_len { 0 => {
let stack_item = try!(u64::from_bytes(&header_buffer[idx*8..(idx+1)*8], &mut fake_stack)); let fixed_size = mem::size_of::<T>();
length_stack.push_back(stack_item as usize); let mut payload_buffer = Vec::with_capacity(fixed_size);
} unsafe { payload_buffer.set_len(fixed_size); }
try!(r.read(&mut payload_buffer).map_err(|_| 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); };
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)
},
} }
}
try!(r.read(&mut size_buffer[..]).map_err(|_| BinaryConvertError)); pub fn deserialize<T: BinaryConvertable>(buffer: &[u8]) -> Result<T, BinaryConvertError> {
let size = try!(u64::from_bytes(&size_buffer[..], &mut fake_stack)) as usize; use std::io::Cursor;
let mut buff = Cursor::new(buffer);
let mut data = Vec::with_capacity(size); deserialize_from::<T, _>(&mut buff)
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> 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
{ {
let mut length_stack = VecDeque::<usize>::new();
let mut fake_stack = VecDeque::new(); let mut fake_stack = VecDeque::new();
let mut size_buffer = [0u8; 8];
let size = t.size(); match T::len_params() {
let mut buffer = Vec::with_capacity(size); 0 => {
unsafe { buffer.set_len(size); } let fixed_size = mem::size_of::<T>();
try!(t.to_bytes(&mut buffer[..], &mut length_stack)); let mut buffer = Vec::with_capacity(fixed_size);
unsafe { buffer.set_len(fixed_size); }
try!(t.to_bytes(&mut buffer[..], &mut fake_stack));
try!(w.write(&buffer[..]).map_err(|_| BinaryConvertError));
Ok(())
},
_ => {
let mut length_stack = VecDeque::<usize>::new();
let mut size_buffer = [0u8; 8];
let stack_len = length_stack.len(); let size = t.size();
try!((stack_len as u64).to_bytes(&mut size_buffer[..], &mut fake_stack)); let mut buffer = Vec::with_capacity(size);
try!(w.write(&size_buffer[..]).map_err(|_| BinaryConvertError)); unsafe { buffer.set_len(size); }
if stack_len > 0 { try!(t.to_bytes(&mut buffer[..], &mut length_stack));
let mut header_buffer = Vec::with_capacity(stack_len * 8);
unsafe { header_buffer.set_len(stack_len * 8); }; let stack_len = length_stack.len();
try!((stack_len as u64).to_bytes(&mut header_buffer[0..8], &mut fake_stack)); try!((stack_len as u64).to_bytes(&mut size_buffer[..], &mut fake_stack));
let mut idx = 0; try!(w.write(&size_buffer[..]).map_err(|_| BinaryConvertError));
loop { if stack_len > 0 {
match length_stack.pop_front() { let mut header_buffer = Vec::with_capacity(stack_len * 8);
Some(val) => try!((val as u64).to_bytes(&mut header_buffer[idx * 8..(idx+1) * 8], &mut fake_stack)), unsafe { header_buffer.set_len(stack_len * 8); };
None => { break; } 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));
} }
idx = idx + 1;
} try!((size as u64).to_bytes(&mut size_buffer[..], &mut fake_stack));
try!(w.write(&header_buffer[..]).map_err(|_| BinaryConvertError)); try!(w.write(&size_buffer[..]).map_err(|_| BinaryConvertError));
try!(w.write(&buffer[..]).map_err(|_| BinaryConvertError));
Ok(())
},
} }
}
try!((size as u64).to_bytes(&mut size_buffer[..], &mut fake_stack)); pub fn serialize<T: BinaryConvertable>(t: &T) -> Result<Vec<u8>, BinaryConvertError> {
try!(w.write(&size_buffer[..]).map_err(|_| BinaryConvertError)); use std::io::Cursor;
let mut buff = Cursor::new(Vec::new());
try!(w.write(&buffer[..]).map_err(|_| BinaryConvertError)); try!(serialize_into(t, &mut buff));
Ok(buff.into_inner())
Ok(())
} }
macro_rules! binary_fixed_size { macro_rules! binary_fixed_size {
@ -226,7 +394,13 @@ macro_rules! binary_fixed_size {
binary_fixed_size!(u64); binary_fixed_size!(u64);
binary_fixed_size!(u32); binary_fixed_size!(u32);
binary_fixed_size!(usize);
binary_fixed_size!(i32);
binary_fixed_size!(bool); binary_fixed_size!(bool);
binary_fixed_size!(U256);
binary_fixed_size!(H256);
binary_fixed_size!(H2048);
binary_fixed_size!(Address);
#[test] #[test]
fn vec_serialize() { fn vec_serialize() {

View File

@ -9,8 +9,6 @@ path = "run.rs"
[dependencies] [dependencies]
"ethcore-ipc" = { path = "../rpc" } "ethcore-ipc" = { path = "../rpc" }
bincode = "*"
serde = "0.7.0"
ethcore-devtools = { path = "../../devtools" } ethcore-devtools = { path = "../../devtools" }
semver = "0.2.0" semver = "0.2.0"
nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" } nanomsg = { git = "https://github.com/ethcore/nanomsg.rs.git" }

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

@ -27,7 +27,11 @@ mod tests {
#[test] #[test]
fn call_service() { fn call_service() {
// method_num = 0, f = 10 (method Service::commit) // method_num = 0, f = 10 (method Service::commit)
let mut socket = TestSocket::new_ready(vec![0, 16, 0, 0, 0, 10]); let mut socket = TestSocket::new_ready(vec![
0, 16,
0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0]);
let service = Service::new(); let service = Service::new();
assert_eq!(0, *service.commits.read().unwrap()); assert_eq!(0, *service.commits.read().unwrap());
@ -41,12 +45,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,
// part count = 3
3, 0, 0, 0, 0, 0, 0, 0,
// part sizes
5, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0, 0, 0, 0, 0,
64, 0, 0, 0, 0, 0, 0, 0,
// total payload length
70, 0, 0, 0, 0, 0, 0, 0,
// protocol version // protocol version
0, 0, 0, 0, 0, 0, 0, 5, b'1', b'.', b'0', b'.', b'0', b'1', b'.', b'0', b'.', b'0',
// api version // api version
0, 0, 0, 0, 0, 0, 0, 5, b'1', b'.', b'0', b'.', b'0', b'1', b'.', b'0', b'.', b'0',
// reserved // reserved
0, 0, 0, 0, 0, 0, 0, 64,
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,
@ -64,24 +76,34 @@ mod tests {
#[test] #[test]
fn call_service_client() { fn call_service_client() {
let mut socket = TestSocket::new(); let mut socket = TestSocket::new();
socket.read_buffer = vec![0, 0, 0, 10]; socket.read_buffer = vec![10, 0, 0, 0];
let service_client = ServiceClient::init(socket); let service_client = ServiceClient::init(socket);
let result = service_client.commit(5); let result = service_client.commit(5);
assert_eq!(vec![0, 16, 0, 0, 0, 5], service_client.socket().borrow().write_buffer.clone()); assert_eq!(
vec![0, 16,
0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0],
service_client.socket().borrow().write_buffer.clone());
assert_eq!(10, result); assert_eq!(10, result);
} }
#[test] #[test]
fn call_service_client_optional() { fn call_service_client_optional() {
let mut socket = TestSocket::new(); let mut socket = TestSocket::new();
socket.read_buffer = vec![0, 0, 0, 10]; socket.read_buffer = vec![10, 0, 0, 0];
let service_client = ServiceClient::init(socket); let service_client = ServiceClient::init(socket);
let result = service_client.rollback(Some(5), 10); let result = service_client.rollback(Some(5), 10);
assert_eq!(vec![0, 17, 1, 0, 0, 0, 5, 0, 0, 0, 10], service_client.socket().borrow().write_buffer.clone()); assert_eq!(vec![
0, 17,
1, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0, 10, 0, 0, 0], service_client.socket().borrow().write_buffer.clone());
assert_eq!(10, result); assert_eq!(10, result);
} }
@ -115,9 +137,12 @@ mod tests {
assert_eq!(vec![ assert_eq!(vec![
// message num.. // message num..
0, 18, 0, 18,
// payload length // variable size length-s
0, 0, 0, 0, 0, 0, 0, 16, 1, 0, 0, 0, 0, 0, 0, 0,
// structure raw bytes (bigendians :( ) 16, 0, 0, 0, 0, 0, 0, 0,
// total length
16, 0, 0, 0, 0, 0, 0, 0,
// items
3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
11, 0, 0, 0, 0, 0, 0, 0], 11, 0, 0, 0, 0, 0, 0, 0],
service_client.socket().borrow().write_buffer.clone()); service_client.socket().borrow().write_buffer.clone());
@ -127,13 +152,19 @@ mod tests {
#[test] #[test]
fn can_invoke_generic_service() { fn can_invoke_generic_service() {
let mut socket = TestSocket::new(); let mut socket = TestSocket::new();
socket.read_buffer = vec![0, 0, 0, 0]; socket.read_buffer = vec![
1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0,
];
let db_client = DBClient::<u64, _>::init(socket); let db_client = DBClient::<u64, _>::init(socket);
let result = db_client.write(vec![0u8; 100]); let result = db_client.write(vec![0u8; 100]);
assert!(result.is_ok()); assert!(result.is_ok());
} }
#[test] #[test]
fn can_handshake_generic_service() { fn can_handshake_generic_service() {
let mut socket = TestSocket::new(); let mut socket = TestSocket::new();

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

@ -20,7 +20,7 @@ mod tests {
use super::super::service::*; use super::super::service::*;
use nanoipc; use nanoipc;
use std::sync::Arc; use std::sync::Arc;
use std::io::{Write, Read}; use std::io::Write;
use std::sync::atomic::{Ordering, AtomicBool}; use std::sync::atomic::{Ordering, AtomicBool};
fn dummy_write(addr: &str, buf: &[u8]) -> (::nanomsg::Socket, ::nanomsg::Endpoint) { fn dummy_write(addr: &str, buf: &[u8]) -> (::nanomsg::Socket, ::nanomsg::Endpoint) {
@ -67,42 +67,4 @@ mod tests {
worker_should_exit.store(true, Ordering::Relaxed); worker_should_exit.store(true, Ordering::Relaxed);
assert!(hs.is_ok()); assert!(hs.is_ok());
} }
#[test]
fn can_receive_dummy_writes_in_thread() {
let url = "ipc:///tmp/parity-test-nano-30.ipc";
let worker_should_exit = Arc::new(AtomicBool::new(false));
let worker_is_ready = Arc::new(AtomicBool::new(false));
let c_worker_should_exit = worker_should_exit.clone();
let c_worker_is_ready = worker_is_ready.clone();
::std::thread::spawn(move || {
let mut worker = init_worker(url);
while !c_worker_should_exit.load(Ordering::Relaxed) {
worker.poll();
c_worker_is_ready.store(true, Ordering::Relaxed);
}
});
while !worker_is_ready.load(Ordering::Relaxed) { }
let (mut _s, _e) = dummy_write(url, &vec![0, 0,
// protocol version
0, 0, 0, 0, 0, 0, 0, 5, b'1', b'.', b'0', b'.', b'0',
// api version
0, 0, 0, 0, 0, 0, 0, 5, b'1', b'.', b'0', b'.', b'0',
// reserved
0, 0, 0, 0, 0, 0, 0, 64,
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,
]);
let mut buf = vec![0u8;1];
_s.read(&mut buf).unwrap();
assert_eq!(1, buf.len());
assert_eq!(1, buf[0]);
worker_should_exit.store(true, Ordering::Relaxed);
}
} }

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
} }

View File

@ -15,5 +15,6 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Parity interprocess hypervisor IPC service //! Parity interprocess hypervisor IPC service
#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/hypervisor_service_cg.rs")); include!(concat!(env!("OUT_DIR"), "/hypervisor_service_cg.rs"));

View File

@ -18,6 +18,10 @@ use std::sync::{RwLock,Arc};
use std::ops::*; use std::ops::*;
use ipc::IpcConfig; use ipc::IpcConfig;
use std::collections::HashMap; use std::collections::HashMap;
use ipc::BinaryConvertable;
use std::mem;
use ipc::binary::BinaryConvertError;
use std::collections::VecDeque;
pub type IpcModuleId = u64; pub type IpcModuleId = u64;