Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
Merge pull request #1500 from ethcore/ipc-enh
Browse files Browse the repository at this point in the history
change IPC codegen to allow attributes
  • Loading branch information
arkpar authored Jul 1, 2016
2 parents c71dff0 + 08048a7 commit b30e7c7
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 14 deletions.
4 changes: 2 additions & 2 deletions ipc/codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ aster = { version = "0.17", default-features = false }
clippy = { version = "^0.*", optional = true }
quasi = { version = "0.11", default-features = false }
quasi_macros = { version = "0.11", optional = true }
syntex = { version = "*", optional = true }
syntex_syntax = { version = "*", optional = true }
syntex = { version = "0.33", optional = true }
syntex_syntax = { version = "0.33", optional = true }
67 changes: 59 additions & 8 deletions ipc/codegen/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,9 +497,9 @@ fn client_generics(builder: &aster::AstBuilder, interface_map: &InterfaceMap) ->
.build()
}

fn client_qualified_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P<Ty> {
fn client_qualified_ident(cx: &ExtCtxt, 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))
aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item))
.with_generics(generics).build()
.build()
}
Expand All @@ -515,7 +515,7 @@ fn client_phantom_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMa
/// 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 client_short_ident = interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item);
let phantom = client_phantom_ident(builder, interface_map);

let client_struct_item = quote_item!(cx,
Expand Down Expand Up @@ -547,9 +547,9 @@ fn push_with_socket_client_implementation(
push: &mut FnMut(Annotatable))
{
let generics = client_generics(builder, interface_map);
let client_ident = client_qualified_ident(builder, interface_map);
let client_ident = client_qualified_ident(cx, builder, interface_map);
let where_clause = &generics.where_clause;
let client_short_ident = interface_map.ident_map.client_ident(builder);
let client_short_ident = interface_map.ident_map.client_ident(cx, builder, &interface_map.original_item);

let implement = quote_item!(cx,
impl $generics ::ipc::WithSocket<S> for $client_ident $where_clause {
Expand Down Expand Up @@ -578,7 +578,7 @@ fn push_client_implementation(
.collect::<Vec<P<ast::ImplItem>>>();

let generics = client_generics(builder, interface_map);
let client_ident = client_qualified_ident(builder, interface_map);
let client_ident = client_qualified_ident(cx, builder, interface_map);
let where_clause = &generics.where_clause;

let handshake_item = quote_impl_item!(cx,
Expand Down Expand Up @@ -682,6 +682,52 @@ fn implement_handshake_arm(
}


fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result<String, ()> {
match lit.node {
ast::LitKind::Str(ref s, _) => Ok(format!("{}", s)),
_ => {
cx.span_err(
lit.span,
&format!("ipc client_ident annotation `{}` must be a string, not `{}`",
name,
::syntax::print::pprust::lit_to_string(lit)));

return Err(());
}
}
}

pub fn get_ipc_meta_items(attr: &ast::Attribute) -> Option<&[P<ast::MetaItem>]> {
match attr.node.value.node {
ast::MetaItemKind::List(ref name, ref items) if name == &"ipc" => {
Some(items)
}
_ => None
}
}

fn client_ident_renamed(cx: &ExtCtxt, item: &ast::Item) -> Option<String> {
for meta_items in item.attrs().iter().filter_map(get_ipc_meta_items) {
for meta_item in meta_items {
let span = meta_item.span;
match meta_item.node {
ast::MetaItemKind::NameValue(ref name, ref lit) if name == &"client_ident" => {
if let Ok(s) = get_str_from_lit(cx, name, lit) {
return Some(s);
}
}
_ => {
cx.span_err(
meta_item.span,
&format!("unknown client_ident container attribute `{}`",
::syntax::print::pprust::meta_item_to_string(meta_item)));
}
}
}
}
None
}

struct InterfaceMap {
pub original_item: Item,
pub item: P<ast::Item>,
Expand All @@ -700,8 +746,13 @@ impl IdentMap {
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 client_ident(&self, cx: &ExtCtxt, builder: &aster::AstBuilder, item: &ast::Item) -> Ident {
if let Some(new_name) = client_ident_renamed(cx, item) {
builder.id(new_name)
}
else {
builder.id(format!("{}Client", self.original_path.segments[0].identifier))
}
}

fn qualified_ident(&self, builder: &aster::AstBuilder) -> Ident {
Expand Down
27 changes: 27 additions & 0 deletions ipc/codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,36 @@ include!("lib.rs.in");

#[cfg(feature = "with-syntex")]
pub fn register(reg: &mut syntex::Registry) {
use syntax::{ast, fold};

#[cfg(feature = "with-syntex")]
fn strip_attributes(krate: ast::Crate) -> ast::Crate {
struct StripAttributeFolder;
impl fold::Folder for StripAttributeFolder {
fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
match attr.node.value.node {
ast::MetaItemKind::List(ref n, _) if n == &"ipc" => { return None; }
_ => {}
}

Some(attr)
}

fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
fold::noop_fold_mac(mac, self)
}
}

fold::Folder::fold_crate(&mut StripAttributeFolder, krate)
}

reg.add_attr("feature(custom_derive)");
reg.add_attr("feature(custom_attribute)");

reg.add_decorator("derive_Ipc", codegen::expand_ipc_implementation);
reg.add_decorator("derive_Binary", serialization::expand_serialization_implementation);

reg.add_post_expansion_pass(strip_attributes);
}

#[cfg(not(feature = "with-syntex"))]
Expand All @@ -67,4 +92,6 @@ pub fn register(reg: &mut rustc_plugin::Registry) {
syntax::parse::token::intern("derive_Binary"),
syntax::ext::base::MultiDecorator(
Box::new(serialization::expand_serialization_implementation)));

reg.register_attribute("ipc".to_owned(), AttributeType::Normal);
}
2 changes: 1 addition & 1 deletion ipc/tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ ethcore-ipc-nano = { path = "../nano" }
ethcore-util = { path = "../../util" }

[build-dependencies]
syntex = "*"
syntex = "0.33"
ethcore-ipc-codegen = { path = "../codegen" }
17 changes: 17 additions & 0 deletions ipc/tests/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ pub fn main() {
registry.expand("", &src, &dst).unwrap();
}

// rpc pass
if {
let src = Path::new("with_attrs.rs.in");
let dst = Path::new(&out_dir).join("with_attrs_ipc.rs");
let mut registry = syntex::Registry::new();
codegen::register(&mut registry);
registry.expand("", &src, &dst).is_ok()
}
// serialization pass
{
let src = Path::new(&out_dir).join("with_attrs_ipc.rs");
let dst = Path::new(&out_dir).join("with_attrs_cg.rs");
let mut registry = syntex::Registry::new();
codegen::register(&mut registry);
registry.expand("", &src, &dst).unwrap();
}

// rpc pass
{
let src = Path::new("binary.rs.in");
Expand Down
6 changes: 3 additions & 3 deletions ipc/tests/examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ mod tests {
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());
service_client.socket().write().unwrap().write_buffer.clone());
assert_eq!(10, result);
}

Expand All @@ -103,7 +103,7 @@ mod tests {
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());
5, 0, 0, 0, 10, 0, 0, 0], service_client.socket().write().unwrap().write_buffer.clone());
assert_eq!(10, result);
}

Expand Down Expand Up @@ -145,7 +145,7 @@ mod tests {
// items
3, 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().write().unwrap().write_buffer.clone());
assert_eq!(true, result);
}

Expand Down
7 changes: 7 additions & 0 deletions ipc/tests/over_nano.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
mod tests {

use super::super::service::*;
use super::super::with_attrs::PrettyNamedClient;
use nanoipc;
use std::sync::Arc;
use std::io::Write;
Expand All @@ -43,6 +44,12 @@ mod tests {
assert!(client.is_ok());
}

#[test]
fn can_create_renamed_client() {
let client = nanoipc::init_duplex_client::<PrettyNamedClient<_>>("ipc:///tmp/parity-nano-test10.ipc");
assert!(client.is_ok());
}

#[test]
fn can_call_handshake() {
let url = "ipc:///tmp/parity-test-nano-20.ipc";
Expand Down
1 change: 1 addition & 0 deletions ipc/tests/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ mod examples;
mod over_nano;
mod nested;
mod binary;
mod with_attrs;
18 changes: 18 additions & 0 deletions ipc/tests/with_attrs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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/>.

#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/with_attrs_cg.rs"));
34 changes: 34 additions & 0 deletions ipc/tests/with_attrs.rs.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// 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;
use std::mem;
use ipc::binary::BinaryConvertError;
use std::collections::VecDeque;

pub struct BadlyNamedService;

#[derive(Ipc)]
#[ipc(client_ident="PrettyNamedClient")]
impl BadlyNamedService {
fn is_zero(&self, x: u64) -> bool {
x == 0
}
}

impl ::ipc::IpcConfig for BadlyNamedService {}

0 comments on commit b30e7c7

Please sign in to comment.