Merge pull request #961 from ethcore/ipc-nested-interfaces
IPC RPC codegen for generic implementation
This commit is contained in:
commit
59f98a2a20
@ -25,6 +25,9 @@ use syntax::ast::{
|
|||||||
PatKind,
|
PatKind,
|
||||||
FunctionRetTy,
|
FunctionRetTy,
|
||||||
Ty,
|
Ty,
|
||||||
|
TraitRef,
|
||||||
|
Ident,
|
||||||
|
Generics,
|
||||||
};
|
};
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
@ -57,15 +60,15 @@ pub fn expand_ipc_implementation(
|
|||||||
|
|
||||||
let builder = aster::AstBuilder::new().span(span);
|
let builder = aster::AstBuilder::new().span(span);
|
||||||
|
|
||||||
let (impl_item, dispatches, replacements) = match implement_interface(cx, &builder, &item, push) {
|
let interface_map = match implement_interface(cx, &builder, &item, push) {
|
||||||
Ok((item, dispatches, replacements)) => (item, dispatches, replacements),
|
Ok(interface_map) => interface_map,
|
||||||
Err(Error) => { return; }
|
Err(Error) => { return; }
|
||||||
};
|
};
|
||||||
|
|
||||||
push_client(cx, &builder, &item, &dispatches, push, &replacements);
|
push_client(cx, &builder, &interface_map, push);
|
||||||
push_handshake_struct(cx, push);
|
push_handshake_struct(cx, push);
|
||||||
|
|
||||||
push(Annotatable::Item(impl_item));
|
push(Annotatable::Item(interface_map.item));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_handshake_struct(cx: &ExtCtxt, push: &mut FnMut(Annotatable)) {
|
fn push_handshake_struct(cx: &ExtCtxt, push: &mut FnMut(Annotatable)) {
|
||||||
@ -95,7 +98,6 @@ fn push_invoke_signature_aster(
|
|||||||
replacements: &HashMap<String, P<Ty>>,
|
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;
|
||||||
let (input_type_name, input_arg_names, input_arg_tys) = if inputs.len() > 0 {
|
let (input_type_name, input_arg_names, input_arg_tys) = if inputs.len() > 0 {
|
||||||
let first_field_name = field_name(builder, &inputs[0]).name.as_str();
|
let first_field_name = field_name(builder, &inputs[0]).name.as_str();
|
||||||
@ -139,7 +141,7 @@ fn push_invoke_signature_aster(
|
|||||||
(None, vec![], vec![])
|
(None, vec![], vec![])
|
||||||
};
|
};
|
||||||
|
|
||||||
let (return_type_name, return_type_ty) = match signature.decl.output {
|
let return_type_ty = match signature.decl.output {
|
||||||
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()
|
||||||
@ -148,9 +150,9 @@ fn push_invoke_signature_aster(
|
|||||||
.struct_(name_str.as_str())
|
.struct_(name_str.as_str())
|
||||||
.field(format!("payload")).ty().build(ty.clone());
|
.field(format!("payload")).ty().build(ty.clone());
|
||||||
push(Annotatable::Item(tree.build()));
|
push(Annotatable::Item(tree.build()));
|
||||||
(Some(name_str.to_owned()), Some(ty.clone()))
|
Some(ty.clone())
|
||||||
}
|
}
|
||||||
_ => (None, None)
|
_ => None
|
||||||
};
|
};
|
||||||
|
|
||||||
Dispatch {
|
Dispatch {
|
||||||
@ -158,7 +160,6 @@ fn push_invoke_signature_aster(
|
|||||||
input_type_name: input_type_name,
|
input_type_name: input_type_name,
|
||||||
input_arg_names: input_arg_names,
|
input_arg_names: input_arg_names,
|
||||||
input_arg_tys: input_arg_tys,
|
input_arg_tys: input_arg_tys,
|
||||||
return_type_name: return_type_name,
|
|
||||||
return_type_ty: return_type_ty,
|
return_type_ty: return_type_ty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,7 +169,6 @@ struct Dispatch {
|
|||||||
input_type_name: Option<String>,
|
input_type_name: Option<String>,
|
||||||
input_arg_names: Vec<String>,
|
input_arg_names: Vec<String>,
|
||||||
input_arg_tys: Vec<P<Ty>>,
|
input_arg_tys: Vec<P<Ty>>,
|
||||||
return_type_name: Option<String>,
|
|
||||||
return_type_ty: Option<P<Ty>>,
|
return_type_ty: Option<P<Ty>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,33 +294,6 @@ fn implement_dispatch_arms(
|
|||||||
.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, replacements) }).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// generates client type for specified server type
|
|
||||||
/// for say `Service` it generates `ServiceClient`
|
|
||||||
fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, item: &Item, push: &mut FnMut(Annotatable)) {
|
|
||||||
let (_, client_ident) = get_item_idents(builder, item);
|
|
||||||
let client_struct_item = quote_item!(cx,
|
|
||||||
pub struct $client_ident <S: ::ipc::IpcSocket> {
|
|
||||||
socket: ::std::cell::RefCell<S>,
|
|
||||||
phantom: ::std::marker::PhantomData<S>,
|
|
||||||
});
|
|
||||||
|
|
||||||
push(Annotatable::Item(client_struct_item.expect(&format!("could not generate client struct for {:?}", client_ident.name))));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// pushes generated code for the client class (type declaration and method invocation implementations)
|
|
||||||
fn push_client(
|
|
||||||
cx: &ExtCtxt,
|
|
||||||
builder: &aster::AstBuilder,
|
|
||||||
item: &Item,
|
|
||||||
dispatches: &[Dispatch],
|
|
||||||
push: &mut FnMut(Annotatable),
|
|
||||||
replacements: &HashMap<String, P<Ty>>,
|
|
||||||
) {
|
|
||||||
push_client_struct(cx, builder, item, push);
|
|
||||||
push_client_implementation(cx, builder, dispatches, item, push, replacements);
|
|
||||||
push_with_socket_client_implementation(cx, builder, item, push);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// returns an expression with the body for single operation that is being sent to server
|
/// returns an expression with the body for single operation that is being sent to server
|
||||||
/// operation itself serializes input, writes to socket and waits for socket to respond
|
/// operation itself serializes input, writes to socket and waits for socket to respond
|
||||||
/// (the latter only if original method signature returns anyting)
|
/// (the latter only if original method signature returns anyting)
|
||||||
@ -344,10 +317,10 @@ fn implement_client_method_body(
|
|||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
index: u16,
|
index: u16,
|
||||||
dispatch: &Dispatch,
|
interface_map: &InterfaceMap,
|
||||||
replacements: &HashMap<String, P<Ty>>,
|
|
||||||
) -> P<ast::Expr>
|
) -> P<ast::Expr>
|
||||||
{
|
{
|
||||||
|
let dispatch = &interface_map.dispatches[index as usize];
|
||||||
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();
|
||||||
@ -356,7 +329,7 @@ fn implement_client_method_body(
|
|||||||
.ty().ref_()
|
.ty().ref_()
|
||||||
.lifetime("'a")
|
.lifetime("'a")
|
||||||
.ty()
|
.ty()
|
||||||
.build(typegen::argument_replacement(builder, replacements, static_ty).unwrap_or(static_ty.clone()));
|
.build(typegen::argument_replacement(builder, &interface_map.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)")
|
||||||
@ -374,7 +347,7 @@ fn implement_client_method_body(
|
|||||||
.ty().ref_()
|
.ty().ref_()
|
||||||
.lifetime("'a")
|
.lifetime("'a")
|
||||||
.ty()
|
.ty()
|
||||||
.build(typegen::argument_replacement(builder, replacements, static_ty).unwrap_or(static_ty.clone()));
|
.build(typegen::argument_replacement(builder, &interface_map.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);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -408,7 +381,7 @@ fn implement_client_method_body(
|
|||||||
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 arg_ty = &dispatch.input_arg_tys[idx];
|
||||||
let replacement = typegen::argument_replacement(builder, replacements, arg_ty);
|
let replacement = typegen::argument_replacement(builder, &interface_map.replacements, arg_ty);
|
||||||
if let Some(ref replacement_ty) = replacement {
|
if let Some(ref replacement_ty) = replacement {
|
||||||
let replacor_ident = ::syntax::print::pprust::ty_to_string(replacement_ty);
|
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::Ident(ext_cx.ident_of(&replacor_ident), ::syntax::parse::token::Plain)));
|
||||||
@ -474,13 +447,13 @@ fn implement_client_method(
|
|||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
index: u16,
|
index: u16,
|
||||||
dispatch: &Dispatch,
|
interface_map: &InterfaceMap,
|
||||||
replacements: &HashMap<String, P<Ty>>,
|
|
||||||
)
|
)
|
||||||
-> ast::ImplItem
|
-> ast::ImplItem
|
||||||
{
|
{
|
||||||
|
let dispatch = &interface_map.dispatches[index as usize];
|
||||||
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, replacements);
|
let body = implement_client_method_body(cx, builder, index, interface_map);
|
||||||
|
|
||||||
let ext_cx = &*cx;
|
let ext_cx = &*cx;
|
||||||
// expanded version of this
|
// expanded version of this
|
||||||
@ -527,18 +500,75 @@ fn implement_client_method(
|
|||||||
signature.unwrap()
|
signature.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn client_generics(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> Generics {
|
||||||
|
let ty_param = aster::ty_param::TyParamBuilder::new(
|
||||||
|
builder.id("S")).trait_bound(
|
||||||
|
builder.path().global().ids(&["ipc", "IpcSocket"]).build()
|
||||||
|
).build().build();
|
||||||
|
|
||||||
|
builder.from_generics(interface_map.generics.clone())
|
||||||
|
.with_ty_param(ty_param)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_qualified_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P<Ty> {
|
||||||
|
let generics = client_generics(builder, interface_map);
|
||||||
|
aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(builder))
|
||||||
|
.with_generics(generics).build()
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_phantom_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P<Ty> {
|
||||||
|
let generics = client_generics(builder, interface_map);
|
||||||
|
aster::ty::TyBuilder::new().phantom_data()
|
||||||
|
.tuple().with_tys(generics.ty_params.iter().map(|x| aster::ty::TyBuilder::new().id(x.ident)))
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generates client type for specified server type
|
||||||
|
/// for say `Service` it generates `ServiceClient`
|
||||||
|
fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap, push: &mut FnMut(Annotatable)) {
|
||||||
|
let generics = client_generics(builder, interface_map);
|
||||||
|
let client_short_ident = interface_map.ident_map.client_ident(builder);
|
||||||
|
let phantom = client_phantom_ident(builder, interface_map);
|
||||||
|
|
||||||
|
let client_struct_item = quote_item!(cx,
|
||||||
|
pub struct $client_short_ident $generics {
|
||||||
|
socket: ::std::cell::RefCell<S>,
|
||||||
|
phantom: $phantom,
|
||||||
|
});
|
||||||
|
|
||||||
|
push(Annotatable::Item(client_struct_item.expect(&format!("could not generate client struct for {:?}", client_short_ident.name))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// pushes generated code for the client class (type declaration and method invocation implementations)
|
||||||
|
fn push_client(
|
||||||
|
cx: &ExtCtxt,
|
||||||
|
builder: &aster::AstBuilder,
|
||||||
|
interface_map: &InterfaceMap,
|
||||||
|
push: &mut FnMut(Annotatable),
|
||||||
|
) {
|
||||||
|
push_client_struct(cx, builder, interface_map, push);
|
||||||
|
push_client_implementation(cx, builder, interface_map, push);
|
||||||
|
push_with_socket_client_implementation(cx, builder, interface_map, push);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fn push_with_socket_client_implementation(
|
fn push_with_socket_client_implementation(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
item: &Item,
|
interface_map: &InterfaceMap,
|
||||||
push: &mut FnMut(Annotatable))
|
push: &mut FnMut(Annotatable))
|
||||||
{
|
{
|
||||||
let (_, client_ident) = get_item_idents(builder, item);
|
let generics = client_generics(builder, interface_map);
|
||||||
|
let client_ident = client_qualified_ident(builder, interface_map);
|
||||||
|
let where_clause = &generics.where_clause;
|
||||||
|
let client_short_ident = interface_map.ident_map.client_ident(builder);
|
||||||
|
|
||||||
let implement = quote_item!(cx,
|
let implement = quote_item!(cx,
|
||||||
impl<S> ::ipc::WithSocket<S> for $client_ident<S> where S: ::ipc::IpcSocket {
|
impl $generics ::ipc::WithSocket<S> for $client_ident $where_clause {
|
||||||
fn init(socket: S) -> $client_ident<S> {
|
fn init(socket: S) -> $client_ident {
|
||||||
$client_ident {
|
$client_short_ident {
|
||||||
socket: ::std::cell::RefCell::new(socket),
|
socket: ::std::cell::RefCell::new(socket),
|
||||||
phantom: ::std::marker::PhantomData,
|
phantom: ::std::marker::PhantomData,
|
||||||
}
|
}
|
||||||
@ -551,20 +581,22 @@ fn push_with_socket_client_implementation(
|
|||||||
fn push_client_implementation(
|
fn push_client_implementation(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
dispatches: &[Dispatch],
|
interface_map: &InterfaceMap,
|
||||||
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 = interface_map.ident_map.qualified_ident(builder);
|
||||||
|
|
||||||
let mut index = -1i32;
|
let mut index = -1i32;
|
||||||
let items = dispatches.iter()
|
let items = interface_map.dispatches.iter()
|
||||||
.map(|dispatch| { index = index + 1; P(implement_client_method(cx, builder, index as u16, dispatch, replacements)) })
|
.map(|_| { index = index + 1; P(implement_client_method(cx, builder, index as u16, interface_map)) })
|
||||||
.collect::<Vec<P<ast::ImplItem>>>();
|
.collect::<Vec<P<ast::ImplItem>>>();
|
||||||
|
|
||||||
|
let generics = client_generics(builder, interface_map);
|
||||||
|
let client_ident = client_qualified_ident(builder, interface_map);
|
||||||
|
let where_clause = &generics.where_clause;
|
||||||
|
|
||||||
let implement = quote_item!(cx,
|
let implement = quote_item!(cx,
|
||||||
impl<S> $client_ident<S> where S: ::ipc::IpcSocket {
|
impl $generics $client_ident $where_clause {
|
||||||
pub fn handshake(&self) -> Result<(), ::ipc::Error> {
|
pub fn handshake(&self) -> Result<(), ::ipc::Error> {
|
||||||
let payload = BinHandshake {
|
let payload = BinHandshake {
|
||||||
protocol_version: $item_ident::protocol_version().to_string(),
|
protocol_version: $item_ident::protocol_version().to_string(),
|
||||||
@ -632,24 +664,6 @@ fn implement_handshake_arm(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_item_idents(builder: &aster::AstBuilder, item: &Item) -> (::syntax::ast::Ident, ::syntax::ast::Ident) {
|
|
||||||
let ty = match item.node {
|
|
||||||
ast::ItemKind::Impl(_, _, _, _, ref ty, _) => ty.clone(),
|
|
||||||
_ => { builder.ty().id("") }
|
|
||||||
};
|
|
||||||
|
|
||||||
let (item_ident, client_ident) = match ty.node {
|
|
||||||
::syntax::ast::TyKind::Path(_, ref path) => {
|
|
||||||
(
|
|
||||||
builder.id(format!("{}", path.segments[0].identifier)),
|
|
||||||
builder.id(format!("{}Client", path.segments[0].identifier))
|
|
||||||
)
|
|
||||||
},
|
|
||||||
_ => { panic!("incompatible implementation"); }
|
|
||||||
};
|
|
||||||
(item_ident, client_ident)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_tys(items: &[&MethodSig]) -> Vec<P<Ty>> {
|
fn collect_tys(items: &[&MethodSig]) -> Vec<P<Ty>> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for signature in items {
|
for signature in items {
|
||||||
@ -661,15 +675,52 @@ fn collect_tys(items: &[&MethodSig]) -> Vec<P<Ty>> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct InterfaceMap {
|
||||||
|
pub original_item: Item,
|
||||||
|
pub item: P<ast::Item>,
|
||||||
|
pub dispatches: Vec<Dispatch>,
|
||||||
|
pub replacements: HashMap<String, P<Ty>>,
|
||||||
|
pub generics: Generics,
|
||||||
|
pub impl_trait: Option<TraitRef>,
|
||||||
|
pub ident_map: IdentMap,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IdentMap {
|
||||||
|
original_path: ast::Path,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IdentMap {
|
||||||
|
fn ident(&self, builder: &aster::AstBuilder) -> Ident {
|
||||||
|
builder.id(format!("{}", ::syntax::print::pprust::path_to_string(&self.original_path)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn client_ident(&self, builder: &aster::AstBuilder) -> Ident {
|
||||||
|
builder.id(format!("{}Client", self.original_path.segments[0].identifier))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn qualified_ident(&self, builder: &aster::AstBuilder) -> Ident {
|
||||||
|
builder.id(format!("{}", ::syntax::print::pprust::path_to_string(&self.original_path).replace("<", "::<")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ty_ident_map(original_ty: &P<Ty>) -> IdentMap {
|
||||||
|
let original_path = match original_ty.node {
|
||||||
|
::syntax::ast::TyKind::Path(_, ref path) => path.clone(),
|
||||||
|
_ => { panic!("incompatible implementation"); }
|
||||||
|
};
|
||||||
|
let ident_map = IdentMap { original_path: original_path };
|
||||||
|
ident_map
|
||||||
|
}
|
||||||
|
|
||||||
/// 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>, HashMap<String, P<Ty>>), Error> {
|
) -> Result<InterfaceMap, Error> {
|
||||||
let (generics, impl_items) = match item.node {
|
let (generics, impl_trait, original_ty, impl_items) = match item.node {
|
||||||
ast::ItemKind::Impl(_, _, ref generics, _, _, ref impl_items) => (generics, impl_items),
|
ast::ItemKind::Impl(_, _, ref generics, ref impl_trait, ref ty, ref impl_items) => (generics, impl_trait, ty, impl_items),
|
||||||
_ => {
|
_ => {
|
||||||
cx.span_err(
|
cx.span_err(
|
||||||
item.span,
|
item.span,
|
||||||
@ -677,17 +728,9 @@ fn implement_interface(
|
|||||||
return Err(Error);
|
return Err(Error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let impl_generics = builder.from_generics(generics.clone()).build();
|
||||||
let impl_generics = builder.from_generics(generics.clone())
|
|
||||||
.add_ty_param_bound(
|
|
||||||
builder.path().global().ids(&["ethcore_ipc"]).build()
|
|
||||||
)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let where_clause = &impl_generics.where_clause;
|
let where_clause = &impl_generics.where_clause;
|
||||||
|
|
||||||
let (ty, _) = get_item_idents(builder, item);
|
|
||||||
|
|
||||||
let mut method_signatures = 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 {
|
||||||
@ -712,7 +755,8 @@ fn implement_interface(
|
|||||||
|
|
||||||
let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
|
let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
|
||||||
|
|
||||||
Ok((quote_item!(cx,
|
let ty = ty_ident_map(&original_ty).ident(builder);
|
||||||
|
let ipc_item = quote_item!(cx,
|
||||||
impl $impl_generics ::ipc::IpcInterface<$ty> for $ty $where_clause {
|
impl $impl_generics ::ipc::IpcInterface<$ty> for $ty $where_clause {
|
||||||
fn dispatch<R>(&self, r: &mut R) -> Vec<u8>
|
fn dispatch<R>(&self, r: &mut R) -> Vec<u8>
|
||||||
where R: ::std::io::Read
|
where R: ::std::io::Read
|
||||||
@ -743,5 +787,15 @@ fn implement_interface(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).unwrap(), dispatch_table, replacements))
|
).unwrap();
|
||||||
|
|
||||||
|
Ok(InterfaceMap {
|
||||||
|
ident_map: ty_ident_map(&original_ty),
|
||||||
|
original_item: item.clone(),
|
||||||
|
item: ipc_item,
|
||||||
|
dispatches: dispatch_table,
|
||||||
|
replacements: replacements,
|
||||||
|
generics: generics.clone(),
|
||||||
|
impl_trait: impl_trait.clone(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,10 @@ fn is_new_entry(path: &Path) -> Option<String> {
|
|||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
let ident = format!("{}", path.segments[0].identifier.name.as_str());
|
let ident = format!("{}", path.segments[0].identifier.name.as_str());
|
||||||
|
ident == "u8" ||
|
||||||
|
ident == "i8" ||
|
||||||
|
ident == "u16" ||
|
||||||
|
ident == "i16" ||
|
||||||
ident == "u32" ||
|
ident == "u32" ||
|
||||||
ident == "u64" ||
|
ident == "u64" ||
|
||||||
ident == "usize" ||
|
ident == "usize" ||
|
||||||
@ -199,13 +203,15 @@ pub fn match_unknown_tys(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
TyKind::Path(_, ref path) => {
|
TyKind::Path(_, ref path) => {
|
||||||
if path.segments.len() > 0 && path.segments[0].identifier.name.as_str() == "Option" ||
|
if path.segments.len() > 0 && {
|
||||||
path.segments[0].identifier.name.as_str() == "Result" {
|
let first_segment = path.segments[0].identifier.name.as_str();
|
||||||
for extra_type in path.segments[0].parameters.types() {
|
first_segment == "Option" || first_segment == "Result" || first_segment == "Vec"
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let extra_type = &path.segments[0].parameters.types()[0];
|
||||||
if !stop_list.contains(extra_type) {
|
if !stop_list.contains(extra_type) {
|
||||||
fringe.push(extra_type);
|
fringe.push(extra_type);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,24 @@ use std::path::Path;
|
|||||||
pub fn main() {
|
pub fn main() {
|
||||||
let out_dir = env::var_os("OUT_DIR").unwrap();
|
let out_dir = env::var_os("OUT_DIR").unwrap();
|
||||||
|
|
||||||
|
// ipc pass
|
||||||
|
{
|
||||||
|
let src = Path::new("nested.rs.in");
|
||||||
|
let dst = Path::new(&out_dir).join("nested_ipc.rs");
|
||||||
|
let mut registry = syntex::Registry::new();
|
||||||
|
codegen::register(&mut registry);
|
||||||
|
registry.expand("", &src, &dst).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// serde pass
|
||||||
|
{
|
||||||
|
let src = Path::new(&out_dir).join("nested_ipc.rs");
|
||||||
|
let dst = Path::new(&out_dir).join("nested_cg.rs");
|
||||||
|
let mut registry = syntex::Registry::new();
|
||||||
|
serde_codegen::register(&mut registry);
|
||||||
|
registry.expand("", &src, &dst).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// ipc pass
|
// ipc pass
|
||||||
{
|
{
|
||||||
let src = Path::new("service.rs.in");
|
let src = Path::new("service.rs.in");
|
||||||
@ -41,4 +59,5 @@ pub fn main() {
|
|||||||
serde_codegen::register(&mut registry);
|
serde_codegen::register(&mut registry);
|
||||||
registry.expand("", &src, &dst).unwrap();
|
registry.expand("", &src, &dst).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use super::super::service::*;
|
use super::super::service::*;
|
||||||
|
use super::super::nested::DBClient;
|
||||||
use ipc::*;
|
use ipc::*;
|
||||||
use devtools::*;
|
use devtools::*;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
@ -121,4 +122,25 @@ mod tests {
|
|||||||
service_client.socket().borrow().write_buffer.clone());
|
service_client.socket().borrow().write_buffer.clone());
|
||||||
assert_eq!(true, result);
|
assert_eq!(true, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_invoke_generic_service() {
|
||||||
|
let mut socket = TestSocket::new();
|
||||||
|
socket.read_buffer = vec![0, 0, 0, 0];
|
||||||
|
let db_client = DBClient::<u64, _>::init(socket);
|
||||||
|
|
||||||
|
let result = db_client.write(vec![0u8; 100]);
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn can_handshake_generic_service() {
|
||||||
|
let mut socket = TestSocket::new();
|
||||||
|
socket.read_buffer = vec![1];
|
||||||
|
let db_client = DBClient::<u64, _>::init(socket);
|
||||||
|
|
||||||
|
let result = db_client.handshake();
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
17
ipc/tests/nested.rs
Normal file
17
ipc/tests/nested.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// 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/>.
|
||||||
|
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/nested_cg.rs"));
|
44
ipc/tests/nested.rs.in
Normal file
44
ipc/tests/nested.rs.in
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// 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 std::sync::RwLock;
|
||||||
|
use std::ops::*;
|
||||||
|
use ipc::IpcConfig;
|
||||||
|
|
||||||
|
pub struct DB<L: Sized> {
|
||||||
|
pub writes: RwLock<u64>,
|
||||||
|
pub reads: RwLock<u64>,
|
||||||
|
pub holdings: L,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait DBWriter {
|
||||||
|
fn write(&self, data: Vec<u8>) -> Result<(), DBError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: Sized> IpcConfig for DB<L> {}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub enum DBError { Write, Read }
|
||||||
|
|
||||||
|
#[derive(Ipc)]
|
||||||
|
impl<L: Sized> DBWriter for DB<L> {
|
||||||
|
fn write(&self, data: Vec<u8>) -> Result<(), DBError> {
|
||||||
|
let mut writes = self.writes.write().unwrap();
|
||||||
|
*writes = *writes + data.len() as u64;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,8 @@
|
|||||||
// 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)]
|
||||||
|
|
||||||
extern crate bincode;
|
extern crate bincode;
|
||||||
extern crate ethcore_ipc as ipc;
|
extern crate ethcore_ipc as ipc;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
@ -26,3 +28,4 @@ extern crate ethcore_util as util;
|
|||||||
pub mod service;
|
pub mod service;
|
||||||
mod examples;
|
mod examples;
|
||||||
mod over_nano;
|
mod over_nano;
|
||||||
|
mod nested;
|
||||||
|
Loading…
Reference in New Issue
Block a user