Merge pull request #946 from ethcore/numbers-serde-bin
IPC serialization for custom parameters
This commit is contained in:
commit
cb4288b861
@ -33,6 +33,9 @@ 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;
|
||||||
@ -54,15 +57,15 @@ pub fn expand_ipc_implementation(
|
|||||||
|
|
||||||
let builder = aster::AstBuilder::new().span(span);
|
let builder = aster::AstBuilder::new().span(span);
|
||||||
|
|
||||||
let (impl_item, dispatches) = match implement_interface(cx, &builder, &item, push) {
|
let (impl_item, dispatches, replacements) = match implement_interface(cx, &builder, &item, push) {
|
||||||
Ok((item, dispatches)) => (item, dispatches),
|
Ok((item, dispatches, replacements)) => (item, dispatches, replacements),
|
||||||
Err(Error) => { return; }
|
Err(Error) => { return; }
|
||||||
};
|
};
|
||||||
|
|
||||||
push_client(cx, &builder, &item, &dispatches, push);
|
push_client(cx, &builder, &item, &dispatches, push, &replacements);
|
||||||
push_handshake_struct(cx, push);
|
push_handshake_struct(cx, push);
|
||||||
|
|
||||||
push(Annotatable::Item(impl_item))
|
push(Annotatable::Item(impl_item));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_handshake_struct(cx: &ExtCtxt, push: &mut FnMut(Annotatable)) {
|
fn push_handshake_struct(cx: &ExtCtxt, push: &mut FnMut(Annotatable)) {
|
||||||
@ -89,6 +92,7 @@ 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 {
|
||||||
|
|
||||||
@ -102,19 +106,27 @@ fn push_invoke_signature_aster(
|
|||||||
|
|
||||||
let mut arg_names = Vec::new();
|
let mut arg_names = Vec::new();
|
||||||
let mut arg_tys = Vec::new();
|
let mut arg_tys = Vec::new();
|
||||||
|
|
||||||
let arg_name = format!("{}", field_name(builder, &inputs[skip-1]).name);
|
let arg_name = format!("{}", field_name(builder, &inputs[skip-1]).name);
|
||||||
let arg_ty = inputs[skip-1].ty.clone();
|
let arg_ty = inputs[skip-1].ty.clone();
|
||||||
|
|
||||||
let mut tree = builder.item()
|
let mut tree = builder.item()
|
||||||
.attr().word("derive(Serialize, Deserialize)")
|
.attr().word("derive(Serialize, Deserialize)")
|
||||||
.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().build(arg_ty.clone());
|
.field(arg_name.as_str()).ty()
|
||||||
|
.build(typegen::argument_replacement(builder, replacements, &arg_ty).unwrap_or(arg_ty.clone()));
|
||||||
|
|
||||||
arg_names.push(arg_name);
|
arg_names.push(arg_name);
|
||||||
arg_tys.push(arg_ty.clone());
|
arg_tys.push(arg_ty);
|
||||||
for arg in inputs.iter().skip(skip) {
|
for arg in inputs.iter().skip(skip) {
|
||||||
let arg_name = format!("{}", field_name(builder, &arg));
|
let arg_name = format!("{}", field_name(builder, &arg));
|
||||||
let arg_ty = arg.ty.clone();
|
|
||||||
tree = tree.field(arg_name.as_str()).ty().build(arg_ty.clone());
|
let mut arg_ty = arg.ty.clone();
|
||||||
|
arg_ty = typegen::argument_replacement(builder, replacements, &arg_ty).unwrap_or(arg_ty);
|
||||||
|
|
||||||
|
tree = tree.field(arg_name.as_str()).ty()
|
||||||
|
.build(typegen::argument_replacement(builder, replacements, &arg_ty).unwrap_or(arg_ty.clone()));
|
||||||
arg_names.push(arg_name);
|
arg_names.push(arg_name);
|
||||||
arg_tys.push(arg_ty);
|
arg_tys.push(arg_ty);
|
||||||
}
|
}
|
||||||
@ -172,14 +184,20 @@ 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 output_type_id = builder.id(dispatch.return_type_name.clone().unwrap().as_str());
|
let output_type_id = builder.id(dispatch.return_type_name.clone().unwrap().as_str());
|
||||||
|
|
||||||
let input_args_exprs = dispatch.input_arg_names.iter().map(|ref 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);
|
||||||
quote_expr!(cx, input. $arg_ident)
|
if typegen::argument_replacement(builder, replacements, &dispatch.input_arg_tys[arg_index]).is_some() {
|
||||||
|
quote_expr!(cx, input. $arg_ident .into())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
quote_expr!(cx, input. $arg_ident)
|
||||||
|
}
|
||||||
}).collect::<Vec<P<ast::Expr>>>();
|
}).collect::<Vec<P<ast::Expr>>>();
|
||||||
|
|
||||||
let ext_cx = &*cx;
|
let ext_cx = &*cx;
|
||||||
@ -236,6 +254,7 @@ 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 {
|
||||||
@ -246,7 +265,7 @@ fn implement_dispatch_arm_invoke(
|
|||||||
|
|
||||||
let input_type_id = builder.id(dispatch.input_type_name.clone().unwrap().as_str());
|
let input_type_id = builder.id(dispatch.input_type_name.clone().unwrap().as_str());
|
||||||
|
|
||||||
let invoke_serialize_stmt = implement_dispatch_arm_invoke_stmt(cx, builder, dispatch);
|
let invoke_serialize_stmt = implement_dispatch_arm_invoke_stmt(cx, builder, dispatch, replacements);
|
||||||
quote_expr!(cx, {
|
quote_expr!(cx, {
|
||||||
let input: $input_type_id = $deserialize_expr;
|
let input: $input_type_id = $deserialize_expr;
|
||||||
$invoke_serialize_stmt
|
$invoke_serialize_stmt
|
||||||
@ -260,10 +279,11 @@ 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);
|
let invoke_expr = implement_dispatch_arm_invoke(cx, builder, dispatch, buffer, replacements);
|
||||||
quote_arm!(cx, $index_ident => { $invoke_expr } )
|
quote_arm!(cx, $index_ident => { $invoke_expr } )
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,11 +292,12 @@ 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) }).collect()
|
.map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch, buffer, replacements) }).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// generates client type for specified server type
|
/// generates client type for specified server type
|
||||||
@ -298,10 +319,11 @@ fn push_client(
|
|||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
item: &Item,
|
item: &Item,
|
||||||
dispatches: &[Dispatch],
|
dispatches: &[Dispatch],
|
||||||
push: &mut FnMut(Annotatable))
|
push: &mut FnMut(Annotatable),
|
||||||
{
|
replacements: &HashMap<String, P<Ty>>,
|
||||||
|
) {
|
||||||
push_client_struct(cx, builder, item, push);
|
push_client_struct(cx, builder, item, push);
|
||||||
push_client_implementation(cx, builder, dispatches, item, push);
|
push_client_implementation(cx, builder, dispatches, item, push, replacements);
|
||||||
push_with_socket_client_implementation(cx, builder, item, push);
|
push_with_socket_client_implementation(cx, builder, item, push);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,15 +351,18 @@ fn implement_client_method_body(
|
|||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
index: u16,
|
index: u16,
|
||||||
dispatch: &Dispatch,
|
dispatch: &Dispatch,
|
||||||
)
|
replacements: &HashMap<String, P<Ty>>,
|
||||||
-> P<ast::Expr>
|
) -> P<ast::Expr>
|
||||||
{
|
{
|
||||||
let request = if dispatch.input_arg_names.len() > 0 {
|
let request = if dispatch.input_arg_names.len() > 0 {
|
||||||
|
|
||||||
let arg_name = dispatch.input_arg_names[0].as_str();
|
let arg_name = dispatch.input_arg_names[0].as_str();
|
||||||
|
let static_ty = &dispatch.input_arg_tys[0];
|
||||||
let arg_ty = builder
|
let arg_ty = builder
|
||||||
.ty().ref_()
|
.ty().ref_()
|
||||||
.lifetime("'a")
|
.lifetime("'a")
|
||||||
.ty().build(dispatch.input_arg_tys[0].clone());
|
.ty()
|
||||||
|
.build(typegen::argument_replacement(builder, replacements, static_ty).unwrap_or(static_ty.clone()));
|
||||||
|
|
||||||
let mut tree = builder.item()
|
let mut tree = builder.item()
|
||||||
.attr().word("derive(Serialize)")
|
.attr().word("derive(Serialize)")
|
||||||
@ -345,15 +370,19 @@ fn implement_client_method_body(
|
|||||||
.generics()
|
.generics()
|
||||||
.lifetime_name("'a")
|
.lifetime_name("'a")
|
||||||
.build()
|
.build()
|
||||||
.field(arg_name).ty().build(arg_ty);
|
.field(arg_name).ty()
|
||||||
|
.build(arg_ty);
|
||||||
|
|
||||||
for arg_idx in 1..dispatch.input_arg_names.len() {
|
for arg_idx in 1..dispatch.input_arg_names.len() {
|
||||||
let arg_name = dispatch.input_arg_names[arg_idx].as_str();
|
let arg_name = dispatch.input_arg_names[arg_idx].as_str();
|
||||||
|
let static_ty = &dispatch.input_arg_tys[arg_idx];
|
||||||
let arg_ty = builder
|
let arg_ty = builder
|
||||||
.ty().ref_()
|
.ty().ref_()
|
||||||
.lifetime("'a")
|
.lifetime("'a")
|
||||||
.ty().build(dispatch.input_arg_tys[arg_idx].clone());
|
.ty()
|
||||||
|
.build(typegen::argument_replacement(builder, replacements, static_ty).unwrap_or(static_ty.clone()));
|
||||||
tree = tree.field(arg_name).ty().build(arg_ty);
|
tree = tree.field(arg_name).ty().build(arg_ty);
|
||||||
|
|
||||||
}
|
}
|
||||||
let mut request_serialization_statements = Vec::new();
|
let mut request_serialization_statements = Vec::new();
|
||||||
|
|
||||||
@ -378,11 +407,28 @@ 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 arg in dispatch.input_arg_names.iter() {
|
for (idx, arg) in dispatch.input_arg_names.iter().enumerate() {
|
||||||
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, 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,11 +480,13 @@ fn implement_client_method(
|
|||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
index: u16,
|
index: u16,
|
||||||
dispatch: &Dispatch)
|
dispatch: &Dispatch,
|
||||||
|
replacements: &HashMap<String, P<Ty>>,
|
||||||
|
)
|
||||||
-> ast::ImplItem
|
-> ast::ImplItem
|
||||||
{
|
{
|
||||||
let method_name = builder.id(dispatch.function_name.as_str());
|
let method_name = builder.id(dispatch.function_name.as_str());
|
||||||
let body = implement_client_method_body(cx, builder, index, dispatch);
|
let body = implement_client_method_body(cx, builder, index, dispatch, replacements);
|
||||||
|
|
||||||
let ext_cx = &*cx;
|
let ext_cx = &*cx;
|
||||||
// expanded version of this
|
// expanded version of this
|
||||||
@ -511,13 +559,14 @@ fn push_client_implementation(
|
|||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
dispatches: &[Dispatch],
|
dispatches: &[Dispatch],
|
||||||
item: &Item,
|
item: &Item,
|
||||||
push: &mut FnMut(Annotatable))
|
push: &mut FnMut(Annotatable),
|
||||||
{
|
replacements: &HashMap<String, P<Ty>>,
|
||||||
|
) {
|
||||||
let (item_ident, client_ident) = get_item_idents(builder, item);
|
let (item_ident, client_ident) = get_item_idents(builder, item);
|
||||||
|
|
||||||
let mut index = -1i32;
|
let mut index = -1i32;
|
||||||
let items = dispatches.iter()
|
let items = dispatches.iter()
|
||||||
.map(|dispatch| { index = index + 1; P(implement_client_method(cx, builder, index as u16, dispatch)) })
|
.map(|dispatch| { index = index + 1; P(implement_client_method(cx, builder, index as u16, dispatch, replacements)) })
|
||||||
.collect::<Vec<P<ast::ImplItem>>>();
|
.collect::<Vec<P<ast::ImplItem>>>();
|
||||||
|
|
||||||
let implement = quote_item!(cx,
|
let implement = quote_item!(cx,
|
||||||
@ -607,13 +656,24 @@ fn get_item_idents(builder: &aster::AstBuilder, item: &Item) -> (::syntax::ast::
|
|||||||
(item_ident, client_ident)
|
(item_ident, client_ident)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
/// implements `IpcInterface<C>` for the given class `C`
|
/// implements `IpcInterface<C>` for the given class `C`
|
||||||
fn implement_interface(
|
fn implement_interface(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
item: &Item,
|
item: &Item,
|
||||||
push: &mut FnMut(Annotatable),
|
push: &mut FnMut(Annotatable),
|
||||||
) -> Result<(P<ast::Item>, Vec<Dispatch>), Error> {
|
) -> Result<(P<ast::Item>, Vec<Dispatch>, HashMap<String, P<Ty>>), Error> {
|
||||||
let (generics, impl_items) = match item.node {
|
let (generics, impl_items) = match item.node {
|
||||||
ast::ItemKind::Impl(_, _, ref generics, _, _, ref impl_items) => (generics, impl_items),
|
ast::ItemKind::Impl(_, _, ref generics, _, _, ref impl_items) => (generics, impl_items),
|
||||||
_ => {
|
_ => {
|
||||||
@ -634,15 +694,27 @@ fn implement_interface(
|
|||||||
|
|
||||||
let (ty, _) = get_item_idents(builder, item);
|
let (ty, _) = get_item_idents(builder, item);
|
||||||
|
|
||||||
let mut dispatch_table = Vec::new();
|
let mut method_signatures = Vec::new();
|
||||||
for impl_item in impl_items {
|
for impl_item in impl_items {
|
||||||
if let ImplItemKind::Method(ref signature, _) = impl_item.node {
|
if let ImplItemKind::Method(ref signature, _) = impl_item.node {
|
||||||
dispatch_table.push(push_invoke_signature_aster(builder, &impl_item, signature, push));
|
method_signatures.push((impl_item, signature))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let dispatch_arms = implement_dispatch_arms(cx, builder, &dispatch_table, false);
|
let all_tys = collect_tys(
|
||||||
let dispatch_arms_buffered = implement_dispatch_arms(cx, builder, &dispatch_table, true);
|
&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)|
|
||||||
|
push_invoke_signature_aster(builder, impl_item, signature, &replacements, push))
|
||||||
|
.collect::<Vec<Dispatch>>();
|
||||||
|
|
||||||
|
let dispatch_arms = implement_dispatch_arms(cx, builder, &dispatch_table, false, &replacements);
|
||||||
|
let dispatch_arms_buffered = implement_dispatch_arms(cx, builder, &dispatch_table, true, &replacements);
|
||||||
|
|
||||||
let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
|
let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
|
||||||
|
|
||||||
@ -676,5 +748,5 @@ fn implement_interface(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).unwrap(), dispatch_table))
|
).unwrap(), dispatch_table, replacements))
|
||||||
}
|
}
|
||||||
|
@ -15,3 +15,4 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
mod codegen;
|
mod codegen;
|
||||||
|
pub mod typegen;
|
||||||
|
231
ipc/codegen/src/typegen.rs
Normal file
231
ipc/codegen/src/typegen.rs
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
// 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 == "u32" ||
|
||||||
|
ident == "u64" ||
|
||||||
|
ident == "usize" ||
|
||||||
|
ident == "i32" ||
|
||||||
|
ident == "i64" ||
|
||||||
|
ident == "String" ||
|
||||||
|
ident == "bool"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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::Path(_, ref path) => {
|
||||||
|
if path.segments.len() > 0 && path.segments[0].identifier.name.as_str() == "Option" ||
|
||||||
|
path.segments[0].identifier.name.as_str() == "Result" {
|
||||||
|
for extra_type in path.segments[0].parameters.types() {
|
||||||
|
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
|
||||||
|
}
|
@ -15,7 +15,7 @@ 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" }
|
||||||
ethcore-ipc-nano = { path = "../nano" }
|
ethcore-ipc-nano = { path = "../nano" }
|
||||||
|
ethcore-util = { path = "../../util" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
syntex = "*"
|
syntex = "*"
|
||||||
|
@ -101,4 +101,24 @@ mod tests {
|
|||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_use_custom_params() {
|
||||||
|
let mut socket = TestSocket::new();
|
||||||
|
socket.read_buffer = vec![1];
|
||||||
|
let service_client = ServiceClient::init(socket);
|
||||||
|
|
||||||
|
let result = service_client.push_custom(CustomData { a: 3, b: 11});
|
||||||
|
|
||||||
|
assert_eq!(vec![
|
||||||
|
// message num..
|
||||||
|
0, 18,
|
||||||
|
// payload length
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 16,
|
||||||
|
// structure raw bytes (bigendians :( )
|
||||||
|
3, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
11, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
service_client.socket().borrow().write_buffer.clone());
|
||||||
|
assert_eq!(true, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ extern crate ethcore_devtools as devtools;
|
|||||||
extern crate semver;
|
extern crate semver;
|
||||||
extern crate nanomsg;
|
extern crate nanomsg;
|
||||||
extern crate ethcore_ipc_nano as nanoipc;
|
extern crate ethcore_ipc_nano as nanoipc;
|
||||||
|
extern crate ethcore_util as util;
|
||||||
|
|
||||||
pub mod service;
|
pub mod service;
|
||||||
mod examples;
|
mod examples;
|
||||||
|
@ -16,13 +16,42 @@
|
|||||||
|
|
||||||
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};
|
||||||
|
|
||||||
pub struct Service {
|
pub struct Service {
|
||||||
pub commits: RwLock<usize>,
|
pub commits: RwLock<usize>,
|
||||||
pub rollbacks: RwLock<usize>,
|
pub rollbacks: RwLock<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CustomData {
|
||||||
|
pub a: usize,
|
||||||
|
pub b: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
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)]
|
||||||
impl Service {
|
impl Service {
|
||||||
fn commit(&self, f: u32) -> u32 {
|
fn commit(&self, f: u32) -> u32 {
|
||||||
@ -36,6 +65,15 @@ impl Service {
|
|||||||
*lock = *lock + a_0 as usize - b as usize;
|
*lock = *lock + a_0 as usize - b as usize;
|
||||||
(a_0 - b) as i32
|
(a_0 - b) as i32
|
||||||
}
|
}
|
||||||
|
pub fn push_custom(&self, data: CustomData) -> bool {
|
||||||
|
let mut clock = self.commits.write().unwrap();
|
||||||
|
let mut rlock = self.commits.write().unwrap();
|
||||||
|
|
||||||
|
*clock = data.a;
|
||||||
|
*rlock = data.b;
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Service {
|
impl Service {
|
||||||
|
Loading…
Reference in New Issue
Block a user