From e0ae0724e21c12b2b0cf3936ef210cfa0ed61ffd Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Wed, 20 Apr 2016 14:17:11 +0300 Subject: [PATCH] initial commit --- ipc/codegen/src/lib.rs | 5 + ipc/codegen/src/lib.rs.in | 1 + ipc/codegen/src/serialization.rs | 202 +++++++++++++++++++++++++++++++ ipc/codegen/src/typegen.rs | 3 +- ipc/rpc/src/binary.rs | 25 ++++ ipc/rpc/src/lib.rs | 2 +- 6 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 ipc/codegen/src/serialization.rs create mode 100644 ipc/rpc/src/binary.rs diff --git a/ipc/codegen/src/lib.rs b/ipc/codegen/src/lib.rs index a29678df0..126aa3a85 100644 --- a/ipc/codegen/src/lib.rs +++ b/ipc/codegen/src/lib.rs @@ -54,6 +54,7 @@ pub fn register(reg: &mut syntex::Registry) { reg.add_attr("feature(custom_attribute)"); reg.add_decorator("derive_Ipc", codegen::expand_ipc_implementation); + reg.add_decorator("derive_Binary", serialization::expand_serialization_implementation); } #[cfg(not(feature = "with-syntex"))] @@ -62,4 +63,8 @@ pub fn register(reg: &mut rustc_plugin::Registry) { syntax::parse::token::intern("derive_Ipc"), syntax::ext::base::MultiDecorator( Box::new(codegen::expand_ipc_implementation))); + reg.register_syntax_extension( + syntax::parse::token::intern("derive_Binary"), + syntax::ext::base::MultiDecorator( + Box::new(serialization::expand_serialization_implementation))); } diff --git a/ipc/codegen/src/lib.rs.in b/ipc/codegen/src/lib.rs.in index 46a2c9ca5..08c8ad998 100644 --- a/ipc/codegen/src/lib.rs.in +++ b/ipc/codegen/src/lib.rs.in @@ -15,4 +15,5 @@ // along with Parity. If not, see . mod codegen; +mod serialization; pub mod typegen; diff --git a/ipc/codegen/src/serialization.rs b/ipc/codegen/src/serialization.rs new file mode 100644 index 000000000..205b13f67 --- /dev/null +++ b/ipc/codegen/src/serialization.rs @@ -0,0 +1,202 @@ +// 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, + TraitRef, + Ident, + Generics, +}; + +use syntax::ast; +use syntax::codemap::Span; +use syntax::ext::base::{Annotatable, ExtCtxt}; +use syntax::ext::build::AstBuilder; +use syntax::ptr::P; + +pub struct Error; + +pub fn expand_serialization_implementation( + cx: &mut ExtCtxt, + span: Span, + meta_item: &MetaItem, + annotatable: &Annotatable, + push: &mut FnMut(Annotatable) +) { + let item = match *annotatable { + Annotatable::Item(ref item) => item, + _ => { + cx.span_err(meta_item.span, "`#[derive(Binary)]` may only be applied to structs and enums"); + return; + } + }; + + let builder = aster::AstBuilder::new().span(span); + + let impl_item = match serialize_item(cx, &builder, &item) { + Ok(item) => item, + Err(Error) => { + // An error occured, but it should have been reported already. + return; + } + }; + + push(Annotatable::Item(impl_item)) +} + +fn serialize_item( + cx: &ExtCtxt, + builder: &aster::AstBuilder, + item: &Item, +) -> Result, Error> { + let generics = match item.node { + ast::ItemKind::Struct(_, ref generics) => generics, + ast::ItemKind::Enum(_, ref generics) => generics, + _ => { + cx.span_err( + item.span, + "`#[derive(Serialize)]` may only be applied to structs and enums"); + return Err(Error); + } + }; + + let impl_generics = build_impl_generics(cx, builder, item, generics); + + let ty = builder.ty().path() + .segment(item.ident).with_generics(impl_generics.clone()).build() + .build(); + + let where_clause = &impl_generics.where_clause; + + let binary_expressions = try!(binary_expr(cx, + &builder, + &item, + &impl_generics, + ty.clone())); + + Ok(quote_item!(cx, + impl $impl_generics ::ipc::BinaryConvertable for $ty $where_clause { + fn size(&self) -> usize { + $size_expr + } + + fn to_bytes(buffer: &mut [u8]) { + $write_expr + } + + fn from_bytes(buffer: &[u8]) -> Self { + $create_expr + } + } + ).unwrap()) +} + +fn binary_expr( + cx: &ExtCtxt, + builder: &aster::AstBuilder, + item: &Item, + impl_generics: &ast::Generics, + ty: P, +) -> Result { + match item.node { + ast::ItemKind::Struct(ref variant_data, _) => { + binary_expr_struct( + cx, + builder, + impl_generics, + ty, + item.span, + variant_data, + ) + } + ast::ItemKind::Enum(ref enum_def, _) => { + binary_expr_enum( + cx, + builder, + item.ident, + impl_generics, + ty, + enum_def, + ) + } + _ => { + cx.span_bug(item.span, + "expected ItemStruct or ItemEnum in #[derive(Serialize)]"); + } + } +} + +struct BinaryExpressions { + size: P, + write: P, + read: P, +} + +fn serialize_tuple_struct( + cx: &ExtCtxt, + builder: &aster::AstBuilder, + impl_generics: &ast::Generics, + ty: P, + fields: usize, +) -> Result, Error> { + let type_name = field.ty; + let id = field.id; + + Ok(BinaryExpressions { + size: quote_expr!(cx, self. $id .size() ), + write: quote_stmt!(cx, self. $id .write(buffer); ), + read: quote_expr!(cx, Self { $id: $type_name ::from_bytes(buffer) }), + }); +} + +fn binary_expr_struct( + cx: &ExtCtxt, + builder: &aster::AstBuilder, + impl_generics: &ast::Generics, + ty: P, + span: Span, + variant_data: &ast::VariantData, +) -> Result { + match *variant_data { + ast::VariantData::Tuple(ref fields, _) => { + binary_expr_struct_tuple( + cx, + &builder, + impl_generics, + ty, + fields, + ) + } + ast::VariantData::Struct(ref fields, _) => { + binary_expr_struct_inner( + cx, + &builder, + impl_generics, + ty, + fields, + ) + } + } +} diff --git a/ipc/codegen/src/typegen.rs b/ipc/codegen/src/typegen.rs index e6e828ee7..0699bccb0 100644 --- a/ipc/codegen/src/typegen.rs +++ b/ipc/codegen/src/typegen.rs @@ -50,7 +50,8 @@ fn is_new_entry(path: &Path) -> Option { ident == "H256" || ident == "U256" || ident == "H2048" || - ident == "Address" + ident == "Address" || + ident == "Bytes" } }; diff --git a/ipc/rpc/src/binary.rs b/ipc/rpc/src/binary.rs new file mode 100644 index 000000000..3b9b0a561 --- /dev/null +++ b/ipc/rpc/src/binary.rs @@ -0,0 +1,25 @@ +// 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 . + +//! Binary representation of types + +trait BinaryConvertable { + fn size(&self) -> usize; + + fn to_bytes(buffer: &mut [u8]); + + fn from_bytes(buffer: &[u8]) -> Self; +} diff --git a/ipc/rpc/src/lib.rs b/ipc/rpc/src/lib.rs index c2165b6e5..c771fb1b1 100644 --- a/ipc/rpc/src/lib.rs +++ b/ipc/rpc/src/lib.rs @@ -21,4 +21,4 @@ extern crate semver; extern crate nanomsg; pub mod interface; -pub use interface::{IpcInterface, IpcSocket, invoke, IpcConfig, Handshake, Error, WithSocket}; +pub use interface::{IpcInterface, IpcSocket, invoke, IpcConfig, Handshake, Error, WithSocket, BinaryConvertable};