From a9cceefaa43cdd6844343638b61820d28bb2b3e2 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 13 Apr 2016 03:46:36 +0300 Subject: [PATCH] mapping and custom serializers --- ipc/codegen/src/codegen.rs | 10 +- ipc/codegen/src/lib.rs.in | 1 + ipc/codegen/src/typegen.rs | 198 +++++++++++++++++++++++++++++++++++++ ipc/serde/Cargo.toml | 16 --- ipc/serde/build.rs | 30 ------ ipc/serde/src/lib.rs | 17 ---- ipc/serde/src/lib.rs.in | 18 ---- ipc/tests/Cargo.toml | 2 +- ipc/tests/run.rs | 1 + ipc/tests/service.rs.in | 28 ++++++ 10 files changed, 238 insertions(+), 83 deletions(-) create mode 100644 ipc/codegen/src/typegen.rs delete mode 100644 ipc/serde/Cargo.toml delete mode 100644 ipc/serde/build.rs delete mode 100644 ipc/serde/src/lib.rs delete mode 100644 ipc/serde/src/lib.rs.in diff --git a/ipc/codegen/src/codegen.rs b/ipc/codegen/src/codegen.rs index 1d2c4765c..f15af2f35 100644 --- a/ipc/codegen/src/codegen.rs +++ b/ipc/codegen/src/codegen.rs @@ -33,6 +33,8 @@ use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::ptr::P; +use super::typegen; + pub struct Error; const RESERVED_MESSAGE_IDS: u16 = 16; @@ -62,7 +64,10 @@ pub fn expand_ipc_implementation( push_client(cx, &builder, &item, &dispatches, push); push_handshake_struct(cx, push); - push(Annotatable::Item(impl_item)) + push(Annotatable::Item(impl_item)); + + let all_tys = dispatches.iter().flat_map(|ref dispatch| &dispatch.input_arg_tys).cloned().collect::>>(); + typegen::match_unknown_tys(cx, &builder, &all_tys, push); } fn push_handshake_struct(cx: &ExtCtxt, push: &mut FnMut(Annotatable)) { @@ -333,6 +338,9 @@ fn implement_client_method_body( -> P { let request = if dispatch.input_arg_names.len() > 0 { + + let substitutes = typegen::match_unknown_tys(cx, builder, dispatch.input_arg_tys + let arg_name = dispatch.input_arg_names[0].as_str(); let arg_ty = builder .ty().ref_() diff --git a/ipc/codegen/src/lib.rs.in b/ipc/codegen/src/lib.rs.in index c942157b1..46a2c9ca5 100644 --- a/ipc/codegen/src/lib.rs.in +++ b/ipc/codegen/src/lib.rs.in @@ -15,3 +15,4 @@ // along with Parity. If not, see . mod codegen; +pub mod typegen; diff --git a/ipc/codegen/src/typegen.rs b/ipc/codegen/src/typegen.rs new file mode 100644 index 000000000..bc18fc440 --- /dev/null +++ b/ipc/codegen/src/typegen.rs @@ -0,0 +1,198 @@ +// 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 . +use aster; + +use syntax::ast::{ + MetaItem, + Item, + ImplItemKind, + ImplItem, + MethodSig, + Arg, + PatKind, + FunctionRetTy, + Ty, + TyKind, + Path, +}; + +use syntax::ast; +use syntax::codemap::Span; +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(builder: &aster::AstBuilder, path: &Path) -> Option { + 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 == "Option" + } + }; + + if known { None } + else { Some(path_str(path)) } +} + +fn path_str(path: &Path) -> String { + let mut res: String = "_".to_owned(); + for segment in path.segments.iter() { + res.push_str(&format!("{}_", segment.identifier.name.as_str())); + } + res +} + +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(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 = 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], + push: &mut FnMut(Annotatable), +) -> HashMap> +{ + 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::>>(); + 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(builder, 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 => {} + } + }, + _ => { panic!("bad parameter in input args: {:?}", ty) } + } + } + + hash_map +} diff --git a/ipc/serde/Cargo.toml b/ipc/serde/Cargo.toml deleted file mode 100644 index 1663526e7..000000000 --- a/ipc/serde/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "ethcore-bin-serde" -version = "0.1.0" -authors = ["Nikolay Volf"] -build = "build.rs" - -[lib] - -[dependencies] -bincode = "*" -serde = "0.7.0" -ethcore-devtools = { path = "../../devtools" } - -[build-dependencies] -syntex = "*" -serde_codegen = "0.7.0" diff --git a/ipc/serde/build.rs b/ipc/serde/build.rs deleted file mode 100644 index 9a147f446..000000000 --- a/ipc/serde/build.rs +++ /dev/null @@ -1,30 +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 . - -extern crate syntex; -extern crate serde_codegen; - -use std::env; -use std::path::Path; - -pub fn main() { - let out_dir = env::var_os("OUT_DIR").unwrap(); - let src = Path::new("src/lib.rs.in"); - let dst = Path::new(&out_dir).join("lib.rs"); - let mut registry = syntex::Registry::new(); - serde_codegen::register(&mut registry); - registry.expand("", &src, &dst).unwrap(); -} diff --git a/ipc/serde/src/lib.rs b/ipc/serde/src/lib.rs deleted file mode 100644 index af29c8f87..000000000 --- a/ipc/serde/src/lib.rs +++ /dev/null @@ -1,17 +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 . - -include!(concat!(env!("OUT_DIR"), "/lib.rs")); diff --git a/ipc/serde/src/lib.rs.in b/ipc/serde/src/lib.rs.in deleted file mode 100644 index 4235e6e76..000000000 --- a/ipc/serde/src/lib.rs.in +++ /dev/null @@ -1,18 +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 . - -#[derive(Serialize, Deserialize)] -struct BinBox([u8; mem::size_of()]); diff --git a/ipc/tests/Cargo.toml b/ipc/tests/Cargo.toml index 7b37a58a4..a9d9d7721 100644 --- a/ipc/tests/Cargo.toml +++ b/ipc/tests/Cargo.toml @@ -15,7 +15,7 @@ ethcore-devtools = { path = "../../devtools" } semver = "0.2.0" nanomsg = "0.5.0" ethcore-ipc-nano = { path = "../nano" } - +ethcore-util = { path = "../../util" } [build-dependencies] syntex = "*" diff --git a/ipc/tests/run.rs b/ipc/tests/run.rs index d3eb15287..ce95f35d4 100644 --- a/ipc/tests/run.rs +++ b/ipc/tests/run.rs @@ -21,6 +21,7 @@ extern crate ethcore_devtools as devtools; extern crate semver; extern crate nanomsg; extern crate ethcore_ipc_nano as nanoipc; +extern crate ethcore_util as util; pub mod service; mod examples; diff --git a/ipc/tests/service.rs.in b/ipc/tests/service.rs.in index f48596e6c..a37875b53 100644 --- a/ipc/tests/service.rs.in +++ b/ipc/tests/service.rs.in @@ -16,13 +16,32 @@ use std::sync::RwLock; use std::ops::*; +use std::convert::*; use ipc::IpcConfig; +use util::bytes::{FromRawBytes, BytesConvertable, FromBytesError}; pub struct Service { pub commits: RwLock, pub rollbacks: RwLock, } +pub struct CustomData { + a: usize, + b: usize, +} + +impl FromRawBytes for CustomData { + fn from_bytes(bytes: &[u8]) -> Result { + Ok(CustomData { a: bytes[0] * 256 + bytes[1], b: bytes[2] * 256 + bytes[3]}) + } +} + +impl BytesConvertable for CustomData { + fn bytes(&self) -> &[u8] { + unsafe { &::std::mem::transmute::<[u8;8]>(self) } + } +} + #[derive(Ipc)] impl Service { fn commit(&self, f: u32) -> u32 { @@ -36,6 +55,15 @@ impl Service { *lock = *lock + a_0 as usize - b as usize; (a_0 - b) as i32 } + pub fn push_custom(&self, data: CustomData) -> bool { + let clock = self.commits.write().unwrap(); + let rlock = self.commits.write().unwrap(); + + *clock = data.a; + *rlock = data.b; + + true + } } impl Service {