,
- input_arg_tys: Vec>,
- return_type_ty: Option
>,
-}
-
-// This is the expanded version of this:
-//
-// let invoke_serialize_stmt = quote_stmt!(cx, {
-// ::bincode::serde::serialize(& $output_type_id { payload: self. $function_name ($hand_param_a, $hand_param_b) }, ::bincode::SizeLimit::Infinite).unwrap()
-// });
-//
-// But the above does not allow comma-separated expressions for arbitrary number
-// of parameters ...$hand_param_a, $hand_param_b, ... $hand_param_n
-fn implement_dispatch_arm_invoke_stmt(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- dispatch: &Dispatch,
-) -> ast::Stmt
-{
- use ::syntax::tokenstream::TokenTree::Token;
- let function_name = builder.id(dispatch.function_name.as_str());
-
- let input_args_exprs = dispatch.input_arg_names.iter().enumerate().map(|(arg_index, arg_name)| {
- let arg_ident = builder.id(arg_name);
- let expr = quote_expr!(cx, input. $arg_ident);
- if has_ptr(&dispatch.input_arg_tys[arg_index]) { quote_expr!(cx, & $expr) }
- else { expr }
- }).collect::>>();
-
- let ext_cx = &*cx;
- ::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
- ext_cx.parse_sess(),
- {
- let _sp = ext_cx.call_site();
- let mut tt = ::std::vec::Vec::new();
-
- tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
-
- if dispatch.return_type_ty.is_some() {
- tt.push(Token(_sp, ::syntax::parse::token::ModSep));
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("ipc"))));
- tt.push(Token(_sp, ::syntax::parse::token::ModSep));
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("binary"))));
- tt.push(Token(_sp, ::syntax::parse::token::ModSep));
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"))));
- tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
- tt.push(Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
- }
-
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"))));
- tt.push(Token(_sp, ::syntax::parse::token::Dot));
- tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter());
- tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
-
- for arg_expr in input_args_exprs {
- tt.extend(::quasi::ToTokens::to_tokens(&arg_expr, ext_cx).into_iter());
- tt.push(Token(_sp, ::syntax::parse::token::Comma));
- }
-
- tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
-
- if dispatch.return_type_ty.is_some() {
- tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
- tt.push(Token(_sp, ::syntax::parse::token::Dot));
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"))));
- tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
- tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
- }
- else {
- tt.push(Token(_sp, ::syntax::parse::token::Semi));
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Vec"))));
- tt.push(Token(_sp, ::syntax::parse::token::ModSep));
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("new"))));
- tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
- tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
-
- }
- tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
-
- tt
- }
- )).unwrap()
-}
-
-fn implement_dispatch_arm_invoke(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- dispatch: &Dispatch,
- buffer: bool,
-) -> P
-{
- let deserialize_expr = if buffer {
- quote_expr!(cx,
- ::ipc::binary::deserialize(buf)
- .unwrap_or_else(|e| { panic!("ipc error while deserializing payload, aborting \n payload: {:?}, \n error: {:?}", buf, e); } )
- )
- } else {
- quote_expr!(cx,
- ::ipc::binary::deserialize_from(r)
- .unwrap_or_else(|e| { panic!("ipc error while deserializing payload, aborting \n error: {:?}", e); } )
- )
- };
-
- let invoke_serialize_stmt = implement_dispatch_arm_invoke_stmt(cx, builder, dispatch);
- dispatch.input_type_name.as_ref().map(|val| {
- let input_type_id = builder.id(val.clone().as_str());
- quote_expr!(cx, {
- let input: $input_type_id = $deserialize_expr;
- $invoke_serialize_stmt
- })
- }).unwrap_or(quote_expr!(cx, { $invoke_serialize_stmt }))
-}
-
-/// generates dispatch match for method id
-fn implement_dispatch_arm(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- index: u32,
- dispatch: &Dispatch,
- buffer: bool,
-) -> ast::Arm
-{
- 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 trace = literal!(builder, "Dispatching: {}", &dispatch.function_name);
- quote_arm!(cx, $index_ident => {
- trace!(target: "ipc", $trace);
- $invoke_expr
- })
-}
-
-fn implement_dispatch_arms(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- dispatches: &[Dispatch],
- buffer: bool,
-) -> Vec
-{
- let mut index = -1;
- dispatches.iter()
- .map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch, buffer) }).collect()
-}
-
-pub fn strip_ptr(ty: &P) -> P {
- if let ast::TyKind::Rptr(_, ref ptr_mut) = ty.node {
- ptr_mut.ty.clone()
- }
- else { ty.clone() }
-}
-
-pub fn has_ptr(ty: &P) -> bool {
- if let ast::TyKind::Rptr(_, ref _ptr_mut) = ty.node {
- true
- }
- else { false }
-}
-
-/// 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
-/// (the latter only if original method signature returns anyting)
-///
-/// assuming expanded class contains method
-/// fn commit(&self, f: u32) -> u32
-///
-/// the expanded implementation will generate method for the client like that
-/// #[binary]
-/// struct Request<'a> {
-/// f: &'a u32,
-/// }
-/// let payload = Request{f: &f,};
-/// let mut socket_ref = self.socket.borrow_mut();
-/// let mut socket = socket_ref.deref_mut();
-/// let serialized_payload = ::bincode::serde::serialize(&payload, ::bincode::SizeLimit::Infinite).unwrap();
-/// ::ipc::invoke(0, &Some(serialized_payload), &mut socket);
-/// while !socket.ready().load(::std::sync::atomic::Ordering::Relaxed) { }
-/// ::bincode::serde::deserialize_from::<_, u32>(&mut socket, ::bincode::SizeLimit::Infinite).unwrap()
-fn implement_client_method_body(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- index: u16,
- interface_map: &InterfaceMap,
-) -> P
-{
- use ::syntax::tokenstream::TokenTree::Token;
-
- let dispatch = &interface_map.dispatches[index as usize];
- let index_ident = builder.id(format!("{}", index + RESERVED_MESSAGE_IDS).as_str());
-
- let request = if dispatch.input_arg_names.len() > 0 {
-
- let arg_name = dispatch.input_arg_names[0].as_str();
- let static_ty = strip_ptr(&dispatch.input_arg_tys[0]);
- let arg_ty = builder
- .ty().ref_()
- .lifetime("'a")
- .ty()
- .build(static_ty.clone());
-
- let mut tree = builder.item()
- .attr().word("binary")
- .struct_("Request")
- .generics()
- .lifetime_name("'a")
- .build()
- .field(arg_name).ty()
- .build(arg_ty);
-
- for arg_idx in 1..dispatch.input_arg_names.len() {
- let arg_name = dispatch.input_arg_names[arg_idx].as_str();
- let static_ty = strip_ptr(&dispatch.input_arg_tys[arg_idx]);
-
- let arg_ty = builder
- .ty().ref_()
- .lifetime("'a")
- .ty()
- .build(static_ty);
- tree = tree.field(arg_name).ty().build(arg_ty);
-
- }
- let mut request_serialization_statements = Vec::new();
-
- let struct_tree = tree.build();
- let struct_stmt = quote_stmt!(cx, $struct_tree);
- request_serialization_statements.push(struct_stmt);
-
- // actually this is just expanded version of this:
- // request_serialization_statements.push(quote_stmt!(cx, let payload = Request { p1: &p1, p2: &p2, ... pn: &pn, }));
- // again, cannot dynamically create expression with arbitrary number of comma-separated members
- request_serialization_statements.push({
- let ext_cx = &*cx;
- ::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
- ext_cx.parse_sess(),
- {
- let _sp = ext_cx.call_site();
- let mut tt = ::std::vec::Vec::new();
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("let"))));
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("payload"))));
- tt.push(Token(_sp, ::syntax::parse::token::Eq));
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Request"))));
- tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
-
- for arg in dispatch.input_arg_names.iter() {
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()))));
- tt.push(Token(_sp, ::syntax::parse::token::Colon));
- tt.push(Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
-
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg.as_str()))));
- tt.push(Token(_sp, ::syntax::parse::token::Comma));
- }
-
- tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
- tt
- }))
- });
-
- request_serialization_statements.push(
- quote_stmt!(cx, let mut socket = self.socket.write().unwrap(); ));
-
- request_serialization_statements.push(
- quote_stmt!(cx, let serialized_payload = ::ipc::binary::serialize(&payload).unwrap()));
-
- request_serialization_statements.push(
- quote_stmt!(cx, ::ipc::invoke($index_ident, &Some(serialized_payload), &mut *socket)));
-
-
- request_serialization_statements
- }
- else {
- let mut request_serialization_statements = Vec::new();
- request_serialization_statements.push(
- quote_stmt!(cx, let mut socket = self.socket.write().unwrap(); ));
- request_serialization_statements.push(
- quote_stmt!(cx, ::ipc::invoke($index_ident, &None, &mut *socket)));
- request_serialization_statements
- };
-
- let trace = literal!(builder, "Invoking: {}", &dispatch.function_name);
- if let Some(ref return_ty) = dispatch.return_type_ty {
- let return_expr = quote_expr!(cx,
- ::ipc::binary::deserialize_from::<$return_ty, _>(&mut *socket).unwrap()
- );
- quote_expr!(cx, {
- trace!(target: "ipc", $trace);
- $request;
- $return_expr
- })
- }
- else {
- quote_expr!(cx, {
- trace!(target: "ipc", $trace);
- $request
- })
- }
-}
-
-/// Generates signature and body (see `implement_client_method_body`)
-/// for the client (signature is identical to the original method)
-fn implement_client_method(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- index: u16,
- interface_map: &InterfaceMap,
-)
- -> ast::ImplItem
-{
- use ::syntax::tokenstream::TokenTree::Token;
-
- let dispatch = &interface_map.dispatches[index as usize];
- let method_name = builder.id(dispatch.function_name.as_str());
- let body = implement_client_method_body(cx, builder, index, interface_map);
-
- let ext_cx = &*cx;
- // expanded version of this
- // pub fn $method_name(&self, p1: p1_ty, p2: p2_ty ... pn: pn_ty, ) [-> return_ty] { $body }
- // looks like it's tricky to build function declaration with aster if body already generated
- let signature = ::syntax::parse::parser::Parser::parse_impl_item(
- &mut ::syntax::parse::new_parser_from_tts(
- ext_cx.parse_sess(),
- {
- let _sp = ext_cx.call_site();
- let mut tt = ::std::vec::Vec::new();
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("fn"))));
- tt.extend(::quasi::ToTokens::to_tokens(&method_name, ext_cx).into_iter());
- tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren)));
- tt.push(Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And)));
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"))));
- tt.push(Token(_sp, ::syntax::parse::token::Comma));
-
- for arg_idx in 0..dispatch.input_arg_names.len() {
- let arg_name = dispatch.input_arg_names[arg_idx].as_str();
- let arg_ty = dispatch.input_arg_tys[arg_idx].clone();
-
- tt.push(Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of(arg_name))));
- tt.push(Token(_sp, ::syntax::parse::token::Colon));
- tt.extend(::quasi::ToTokens::to_tokens(&arg_ty, ext_cx).into_iter());
- tt.push(Token(_sp, ::syntax::parse::token::Comma));
- }
- tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren)));
-
- if let Some(ref return_ty) = dispatch.return_type_ty {
- tt.push(Token(_sp, ::syntax::parse::token::RArrow));
- tt.extend(::quasi::ToTokens::to_tokens(return_ty, ext_cx).into_iter());
- }
-
- tt.push(Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace)));
- tt.extend(::quasi::ToTokens::to_tokens(&body, ext_cx).into_iter());
- tt.push(Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace)));
-
- tt
- }));
-
- 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(cx: &ExtCtxt, builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P {
- let generics = client_generics(builder, interface_map);
- aster::ty::TyBuilder::new().path().segment(interface_map.ident_map.client_ident(cx, builder))
- .with_generics(generics).build()
- .build()
-}
-
-fn client_phantom_ident(builder: &aster::AstBuilder, interface_map: &InterfaceMap) -> P {
- 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(cx, builder);
- let phantom = client_phantom_ident(builder, interface_map);
-
- let client_struct_item = quote_item!(cx,
- pub struct $client_short_ident $generics {
- socket: ::std::sync::RwLock,
- 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(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- interface_map: &InterfaceMap,
- push: &mut FnMut(Annotatable))
-{
- let generics = client_generics(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(cx, builder);
-
- let implement = quote_item!(cx,
- impl $generics ::ipc::WithSocket for $client_ident $where_clause {
- fn init(socket: S) -> $client_ident {
- $client_short_ident {
- socket: ::std::sync::RwLock::new(socket),
- phantom: ::std::marker::PhantomData,
- }
- }
- }).unwrap();
- push(Annotatable::Item(implement));
-}
-
-/// pushes full client side code for the original class exposed via ipc
-fn push_client_implementation(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- interface_map: &InterfaceMap,
- push: &mut FnMut(Annotatable),
-) {
- let mut index = -1i32;
- let items = interface_map.dispatches.iter()
- .map(|_| { index = index + 1; P(implement_client_method(cx, builder, index as u16, interface_map)) })
- .collect::>>();
-
- let generics = client_generics(builder, interface_map);
- let client_ident = client_qualified_ident(cx, builder, interface_map);
- let where_clause = &generics.where_clause;
- let endpoint = interface_map.endpoint;
-
- let handshake_item = quote_impl_item!(cx,
- pub fn handshake(&self) -> Result<(), ::ipc::Error> {
- let payload = ::ipc::Handshake {
- protocol_version: $endpoint::protocol_version(),
- api_version: $endpoint::api_version(),
- };
-
- ::ipc::invoke(
- 0,
- &Some(::ipc::binary::serialize(&::ipc::BinHandshake::from(payload)).unwrap()),
- &mut *self.socket.write().unwrap());
-
- let mut result = vec![0u8; 1];
- if try!(self.socket.write().unwrap().read(&mut result).map_err(|_| ::ipc::Error::HandshakeFailed)) == 1 {
- match result[0] {
- 1 => Ok(()),
- _ => Err(::ipc::Error::RemoteServiceUnsupported),
- }
- }
- else { Err(::ipc::Error::HandshakeFailed) }
- }).unwrap();
-
- let socket_item = quote_impl_item!(cx,
- #[cfg(test)]
- pub fn socket(&self) -> &::std::sync::RwLock {
- &self.socket
- }).unwrap();
-
- let generic_items = vec![P(handshake_item), P(socket_item)];
-
- if interface_map.impl_trait.is_some() {
- let trait_ty = builder.id(
- ::syntax::print::pprust::path_to_string(
- &interface_map.impl_trait.as_ref().unwrap().path));
-
- let implement_trait =
- quote_item!(cx,
- impl $generics $trait_ty for $client_ident $where_clause {
- $items
- }
- ).unwrap();
- push(Annotatable::Item(implement_trait));
-
- let implement =
- quote_item!(cx,
- impl $generics $client_ident $where_clause {
- $generic_items
- }
- ).unwrap();
- push(Annotatable::Item(implement));
- }
- else {
- let pub_items = items.iter().map(|item| {
- let pub_item = item.clone();
- pub_item.map(|mut val| { val.vis = ast::Visibility::Public; val })
- }).collect::>>();
-
- let implement = quote_item!(cx,
- impl $generics $client_ident $where_clause {
- $pub_items
- $generic_items
- }).unwrap();
- push(Annotatable::Item(implement));
- }
-
-}
-
-/// implements dispatching of system handshake invocation (method_num 0)
-fn implement_handshake_arm(
- cx: &ExtCtxt,
-) -> (ast::Arm, ast::Arm)
-{
- let handshake_deserialize = quote_stmt!(&cx,
- let handshake_payload = ::ipc::binary::deserialize_from::<::ipc::BinHandshake, _>(r).unwrap();
- );
-
- let handshake_deserialize_buf = quote_stmt!(&cx,
- let handshake_payload = ::ipc::binary::deserialize::<::ipc::BinHandshake>(buf).unwrap();
- );
-
- let handshake_serialize = quote_expr!(&cx,
- ::ipc::binary::serialize::(&Self::handshake(&handshake_payload.to_semver())).unwrap()
- );
-
- (
- quote_arm!(&cx, 0 => {
- $handshake_deserialize
- $handshake_serialize
- }),
- quote_arm!(&cx, 0 => {
- $handshake_deserialize_buf
- $handshake_serialize
- }),
- )
-}
-
-fn get_str_from_lit(cx: &ExtCtxt, name: &str, lit: &ast::Lit) -> Result {
- 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(());
- }
- }
-}
-
-fn client_ident_renamed(cx: &ExtCtxt, meta_item: &MetaItem) -> Option {
- if let ast::MetaItemKind::List(ref list) = meta_item.node {
- for nested in list {
- match nested.node {
- ast::NestedMetaItemKind::MetaItem(ref meta_item) => {
- let is_client_ident = &*meta_item.name.as_str() == "client_ident";
- match meta_item.node {
- ast::MetaItemKind::NameValue(ref lit) if is_client_ident => {
- if let Ok(s) = get_str_from_lit(cx, "client_ident", 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,
- pub dispatches: Vec,
- pub generics: Generics,
- pub impl_trait: Option,
- pub ident_map: IdentMap,
- pub endpoint: Ident,
-}
-
-struct IdentMap {
- original_path: ast::Path,
- meta_item: MetaItem,
-}
-
-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, cx: &ExtCtxt, builder: &aster::AstBuilder) -> Ident {
- if let Some(new_name) = client_ident_renamed(cx, &self.meta_item) {
- builder.id(new_name)
- }
- else {
- builder.id(format!("{}Client", self.original_path.segments[0].identifier))
- }
- }
-}
-
-fn ty_ident_map(original_ty: &P, meta_item: &MetaItem) -> 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, meta_item: meta_item.clone() };
- ident_map
-}
-
-/// implements `IpcInterface` for the given class `C`
-fn implement_interface(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- item: &Item,
- push: &mut FnMut(Annotatable),
- meta_item: &MetaItem,
-) -> Result {
- let (generics, impl_trait, original_ty, dispatch_table) = match item.node {
- ast::ItemKind::Impl(_, _, ref generics, ref impl_trait, ref ty, ref impl_items) => {
- let mut method_signatures = Vec::new();
- for impl_item in impl_items {
- if let ImplItemKind::Method(ref signature, _) = impl_item.node {
- method_signatures.push(NamedSignature { ident: &impl_item.ident, sig: signature });
- }
- }
-
- let dispatch_table = method_signatures.iter().map(|named_signature|
- push_invoke_signature_aster(builder, named_signature, push))
- .collect::>();
-
- (generics, impl_trait.clone(), ty.clone(), dispatch_table)
- },
- ast::ItemKind::Trait(_, ref generics, _, ref trait_items) => {
- let mut method_signatures = Vec::new();
- for trait_item in trait_items {
- if let TraitItemKind::Method(ref signature, _) = trait_item.node {
- method_signatures.push(NamedSignature { ident: &trait_item.ident, sig: signature });
- }
- }
-
- let dispatch_table = method_signatures.iter().map(|named_signature|
- push_invoke_signature_aster(builder, named_signature, push))
- .collect::>();
-
- (
- generics,
- Some(ast::TraitRef {
- path: builder.path().ids(&[item.ident.name]).build(),
- ref_id: item.id,
- }),
- builder.ty().id(item.ident),
- dispatch_table
- )
- },
- _ => {
- cx.span_err(
- item.span,
- "`#[ipc]` may only be applied to implementations and traits");
- return Err(Error);
- },
- };
- let impl_generics = builder.from_generics(generics.clone()).build();
- let where_clause = &impl_generics.where_clause;
-
- let dispatch_arms = implement_dispatch_arms(cx, builder, &dispatch_table, false);
- let dispatch_arms_buffered = implement_dispatch_arms(cx, builder, &dispatch_table, true);
-
- let (handshake_arm, handshake_arm_buf) = implement_handshake_arm(cx);
-
- let ty = ty_ident_map(&original_ty, meta_item).ident(builder);
- let (interface_endpoint, host_generics) = match impl_trait {
- Some(ref trait_) => (builder.id(::syntax::print::pprust::path_to_string(&trait_.path)), None),
- None => (ty, Some(&impl_generics)),
- };
-
- let ipc_item = quote_item!(cx,
- impl $host_generics ::ipc::IpcInterface for $interface_endpoint $where_clause {
- fn dispatch(&self, r: &mut R) -> Vec
- where R: ::std::io::Read
- {
- let mut method_num = vec![0u8;2];
- match r.read(&mut method_num) {
- Ok(size) if size == 0 => { panic!("method id not supplied" ); }
- Err(e) => { panic!("ipc read error: {:?}, aborting", e); }
- _ => { }
- }
-
- // method_num is a 16-bit little-endian unsigned number
- match method_num[1] as u16 + (method_num[0] as u16)*256 {
- // handshake
- $handshake_arm
- // user methods
- $dispatch_arms
- _ => vec![]
- }
- }
-
- fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec
- {
- match method_num {
- $handshake_arm_buf
- $dispatch_arms_buffered
- _ => vec![]
- }
- }
- }
- ).unwrap();
-
- Ok(InterfaceMap {
- ident_map: ty_ident_map(&original_ty, meta_item),
- original_item: item.clone(),
- item: ipc_item,
- dispatches: dispatch_table,
- generics: generics.clone(),
- impl_trait: impl_trait.clone(),
- endpoint: interface_endpoint,
- })
-}
diff --git a/ipc/codegen/src/lib.rs b/ipc/codegen/src/lib.rs
deleted file mode 100644
index 6e7fc441b..000000000
--- a/ipc/codegen/src/lib.rs
+++ /dev/null
@@ -1,237 +0,0 @@
-// Copyright 2015-2017 Parity Technologies (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 .
-
-//! Codegen for IPC RPC
-
-#![cfg_attr(feature = "nightly-testing", plugin(clippy))]
-#![cfg_attr(feature = "nightly-testing", feature(plugin))]
-#![cfg_attr(feature = "nightly-testing", allow(used_underscore_binding))]
-#![cfg_attr(not(feature = "with-syntex"), feature(rustc_private, plugin))]
-#![cfg_attr(not(feature = "with-syntex"), plugin(quasi_macros))]
-
-extern crate aster;
-extern crate quasi;
-
-#[cfg(feature = "with-syntex")]
-extern crate syntex;
-
-#[cfg(feature = "with-syntex")]
-extern crate syntex_syntax as syntax;
-
-#[cfg(not(feature = "with-syntex"))]
-#[macro_use]
-extern crate syntax;
-
-#[cfg(not(feature = "with-syntex"))]
-extern crate rustc_plugin;
-
-#[cfg(not(feature = "with-syntex"))]
-use syntax::feature_gate::AttributeType;
-
-#[cfg(feature = "with-syntex")]
-use syntax::{ast, fold};
-
-
-#[cfg(feature = "with-syntex")]
-include!(concat!(env!("OUT_DIR"), "/lib.rs"));
-
-#[cfg(not(feature = "with-syntex"))]
-include!("lib.rs.in");
-
-#[cfg(feature = "with-syntex")]
-pub fn expand(src: &std::path::Path, dst: &std::path::Path) {
- let mut registry = syntex::Registry::new();
- register(&mut registry);
- registry.expand("", src, dst).unwrap();
-}
-
-#[cfg(feature = "with-syntex")]
-struct StripAttributeFolder<'a> {
- attr_title: &'a str,
-}
-
-#[cfg(feature = "with-syntex")]
-impl<'a> fold::Folder for StripAttributeFolder<'a> {
- fn fold_attribute(&mut self, attr: ast::Attribute) -> Option {
- let is_self = &*attr.value.name.as_str() == self.attr_title;
-
- match attr.value.node {
- ast::MetaItemKind::List(_) if is_self => { return None; }
- ast::MetaItemKind::Word if is_self => { return None; }
- _ => {}
- }
-
- Some(attr)
- }
-
- fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
- fold::noop_fold_mac(mac, self)
- }
-}
-
-#[cfg(feature = "with-syntex")]
-pub fn register_cleaner_ipc(reg: &mut syntex::Registry) {
- #[cfg(feature = "with-syntex")]
- fn strip_attributes(krate: ast::Crate) -> ast::Crate {
- let mut folder = StripAttributeFolder { attr_title: "ipc" };
- fold::Folder::fold_crate(&mut folder, krate)
- }
-
- reg.add_post_expansion_pass(strip_attributes);
-}
-
-#[cfg(feature = "with-syntex")]
-pub fn register_cleaner_binary(reg: &mut syntex::Registry) {
- #[cfg(feature = "with-syntex")]
- fn strip_attributes(krate: ast::Crate) -> ast::Crate {
- let mut folder = StripAttributeFolder { attr_title: "binary" };
- fold::Folder::fold_crate(&mut folder, krate)
- }
-
- reg.add_post_expansion_pass(strip_attributes);
-}
-
-#[cfg(feature = "with-syntex")]
-pub fn register(reg: &mut syntex::Registry) {
- reg.add_attr("feature(custom_derive)");
- reg.add_attr("feature(custom_attribute)");
-
- reg.add_decorator("ipc", codegen::expand_ipc_implementation);
- reg.add_decorator("binary", serialization::expand_serialization_implementation);
-
- register_cleaner_ipc(reg);
- register_cleaner_binary(reg);
-}
-
-#[cfg(not(feature = "with-syntex"))]
-pub fn register(reg: &mut rustc_plugin::Registry) {
- reg.register_syntax_extension(
- syntax::parse::token::intern("ipc"),
- syntax::ext::base::MultiDecorator(
- Box::new(codegen::expand_ipc_implementation)));
- reg.register_syntax_extension(
- syntax::parse::token::intern("binary"),
- syntax::ext::base::MultiDecorator(
- Box::new(serialization::expand_serialization_implementation)));
-
- reg.register_attribute("ipc".to_owned(), AttributeType::Normal);
- reg.register_attribute("binary".to_owned(), AttributeType::Normal);
-}
-
-#[derive(Debug)]
-pub enum Error { InvalidFileName, ExpandFailure, Io(std::io::Error) }
-
-impl std::convert::From for Error {
- fn from(err: std::io::Error) -> Self {
- Error::Io(err)
- }
-}
-
-pub fn derive_ipc_cond(src_path: &str, has_feature: bool) -> Result<(), Error> {
- if has_feature { derive_ipc(src_path) }
- else { cleanup_ipc(src_path) }
-}
-
-pub fn cleanup_ipc(src_path: &str) -> Result<(), Error> {
- cleanup(src_path, AttributeKind::Ipc)
-}
-
-pub fn cleanup_binary(src_path: &str) -> Result<(), Error> {
- cleanup(src_path, AttributeKind::Binary)
-}
-
-enum AttributeKind {
- Ipc,
- Binary,
-}
-
-fn cleanup(src_path: &str, attr: AttributeKind) -> Result<(), Error> {
- use std::env;
- use std::path::{Path, PathBuf};
-
- let out_dir = env::var_os("OUT_DIR").unwrap();
- let file_name = PathBuf::from(src_path).file_name().ok_or(Error::InvalidFileName).map(|val| val.to_str().unwrap().to_owned())?;
- let mut registry = syntex::Registry::new();
-
- match attr {
- AttributeKind::Ipc => { register_cleaner_ipc(&mut registry); }
- AttributeKind::Binary => { register_cleaner_binary(&mut registry); }
- }
-
- if let Err(_) = registry.expand("", &Path::new(src_path), &Path::new(&out_dir).join(&file_name))
- {
- // will be reported by compiler
- return Err(Error::ExpandFailure)
- }
- Ok(())
-}
-
-pub fn derive_ipc(src_path: &str) -> Result<(), Error> {
- use std::env;
- use std::path::{Path, PathBuf};
-
- let out_dir = env::var_os("OUT_DIR").unwrap();
- let file_name = PathBuf::from(src_path).file_name().ok_or(Error::InvalidFileName).map(|val| val.to_str().unwrap().to_owned())?;
-
- let final_path = Path::new(&out_dir).join(&file_name);
-
- let mut intermediate_file_name = file_name.clone();
- intermediate_file_name.push_str(".rpc.in");
- let intermediate_path = Path::new(&out_dir).join(&intermediate_file_name);
-
- {
- let mut registry = syntex::Registry::new();
- register(&mut registry);
- if let Err(_) = registry.expand("", &Path::new(src_path), &intermediate_path) {
- // will be reported by compiler
- return Err(Error::ExpandFailure)
- }
- }
-
- {
- let mut registry = syntex::Registry::new();
- register(&mut registry);
- if let Err(_) = registry.expand("", &intermediate_path, &final_path) {
- // will be reported by compiler
- return Err(Error::ExpandFailure)
- }
- }
-
- Ok(())
-}
-
-pub fn derive_binary(src_path: &str) -> Result<(), Error> {
- use std::env;
- use std::path::{Path, PathBuf};
-
- let out_dir = env::var_os("OUT_DIR").unwrap();
- let file_name = PathBuf::from(src_path).file_name().ok_or(Error::InvalidFileName).map(|val| val.to_str().unwrap().to_owned())?;
- let final_path = Path::new(&out_dir).join(&file_name);
-
- let mut registry = syntex::Registry::new();
- register(&mut registry);
- if let Err(_) = registry.expand("", &Path::new(src_path), &final_path) {
- // will be reported by compiler
- return Err(Error::ExpandFailure)
- }
-
- Ok(())
-}
-
-pub fn derive_binary_cond(src_path: &str, has_feature: bool) -> Result<(), Error> {
- if has_feature { derive_binary(src_path) }
- else { cleanup_binary(src_path) }
-}
diff --git a/ipc/codegen/src/lib.rs.in b/ipc/codegen/src/lib.rs.in
deleted file mode 100644
index c8aa8ebf2..000000000
--- a/ipc/codegen/src/lib.rs.in
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2015-2017 Parity Technologies (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 .
-
-mod codegen;
-mod serialization;
diff --git a/ipc/codegen/src/serialization.rs b/ipc/codegen/src/serialization.rs
deleted file mode 100644
index fd908725c..000000000
--- a/ipc/codegen/src/serialization.rs
+++ /dev/null
@@ -1,810 +0,0 @@
-// Copyright 2015-2017 Parity Technologies (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,
- Ident,
-};
-
-use syntax::ast;
-use syntax::codemap::Span;
-use syntax::ext::base::{Annotatable, ExtCtxt};
-use syntax::ptr::P;
-
-pub struct Error;
-
-use super::codegen;
-
-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 occurred, 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(Binary)]` may only be applied to structs and enums");
- return Err(Error);
- },
- };
-
- let ty = builder.ty().path()
- .segment(item.ident).with_generics(generics.clone()).build()
- .build();
-
- let where_clause = &generics.where_clause;
-
- let binary_expressions = try!(binary_expr(cx,
- &builder,
- &item,
- &generics,
- ty.clone()));
-
- let (size_expr, read_expr, write_expr) =
- (binary_expressions.size, binary_expressions.read, binary_expressions.write);
-
- match quote_item!(cx,
- impl $generics ::ipc::BinaryConvertable for $ty $where_clause {
- fn size(&self) -> usize {
- $size_expr
- }
-
- fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut ::std::collections::VecDeque) -> Result<(), ::ipc::BinaryConvertError> {
- $write_expr
- }
-
- fn from_bytes(buffer: &[u8], length_stack: &mut ::std::collections::VecDeque) -> Result {
- $read_expr
- }
-
- fn len_params() -> usize {
- 1
- }
- })
- {
- Some(item) => Ok(item),
- None => {
- cx.span_err(
- item.span,
- "syntax error expanding serialization implementation");
- Err(Error)
- }
- }
-}
-
-#[allow(unreachable_code)]
-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_item_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,
- item.span,
- enum_def,
- )
- },
- _ => {
- cx.span_bug(item.span,
- "expected ItemStruct or ItemEnum in #[derive(Binary)]");
- Err(Error) as Result
- },
- }
-}
-
-struct BinaryExpressions {
- pub size: P,
- pub write: P,
- pub read: P,
-}
-
-fn replace_qualified(s: &str) -> String {
- if let Some(pos) = s.find("<") {
- let mut source = s.to_owned();
- source.insert(pos, ':');
- source.insert(pos, ':');
- source
- }
- else { s.to_owned() }
-}
-
-fn binary_expr_struct(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- ty: P,
- fields: &[ast::StructField],
- value_ident: Option,
- instance_ident: Option,
-) -> Result {
-
- let size_exprs: Vec> = fields.iter().enumerate().map(|(index, field)| {
- let raw_ident = ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty));
- let index_ident = builder.id(format!("__field{}", index));
- let field_id = match field.ident {
- Some(ident) => builder.id(ident),
- None => builder.id(format!("{}", index)),
- };
-
- match raw_ident.as_ref() {
- "u8" => {
- quote_expr!(cx, 1)
- },
- "[u8]" => {
- value_ident.and_then(|x| {
- Some(quote_expr!(cx, $x. $field_id .len()))
- })
- .unwrap_or_else(|| {
- quote_expr!(cx, $index_ident .len())
- }
- )
- }
- _ => {
- let field_type_ident = builder.id(
- &::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)));
-
- let field_type_ident_qualified = builder.id(
- replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))));
-
- value_ident.and_then(|x|
- {
- Some(quote_expr!(cx,
- match $field_type_ident_qualified::len_params() {
- 0 => ::std::mem::size_of::<$field_type_ident>(),
- _ => $x. $field_id .size(),
- }))
- })
- .unwrap_or_else(|| {
- quote_expr!(cx, match $field_type_ident_qualified::len_params() {
- 0 => ::std::mem::size_of::<$field_type_ident>(),
- _ => $index_ident .size(),
- })
- })
- }
- }
- }).collect();
-
- let first_size_expr = size_exprs[0].clone();
- let mut total_size_expr = quote_expr!(cx, 0usize + $first_size_expr);
- for index in 1..size_exprs.len() {
- let next_expr = size_exprs[index].clone();
- total_size_expr = quote_expr!(cx, $total_size_expr + $next_expr);
- }
-
- let mut write_stmts = Vec::::new();
- write_stmts.push(quote_stmt!(cx, let mut offset = 0usize;).expect("stmt1"));
-
- let mut map_stmts = Vec::::new();
- let field_amount = builder.id(&format!("{}",fields.len()));
- map_stmts.push(quote_stmt!(cx, let mut map = vec![0usize; $field_amount];).expect("stmt2"));
- map_stmts.push(quote_stmt!(cx, let mut total = 0usize;).expect("stmt3"));
-
- let mut post_write_stmts = Vec::::new();
-
- for (index, field) in fields.iter().enumerate() {
- let field_type_ident = builder.id(
- &::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty)));
-
- let field_type_ident_qualified = builder.id(
- replace_qualified(&::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty))));
-
- let field_id = match field.ident {
- Some(ident) => builder.id(ident),
- None => builder.id(format!("{}", index)),
- };
- let member_expr = match value_ident {
- Some(x) => {
- quote_expr!(cx, $x . $field_id)
- },
- None => {
- let index_ident = builder.id(format!("__field{}", index));
- quote_expr!(cx, $index_ident)
- },
- };
-
- let raw_ident = ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty));
- let range_ident = builder.id(format!("r{}", index));
-
- let error_message = "Error serializing member: ".to_owned() + &::syntax::print::pprust::expr_to_string(&member_expr);
- let _error_message_literal = builder.expr().lit().str::<&str>(&error_message);
-
- match raw_ident.as_ref() {
- "u8" => {
- write_stmts.push(quote_stmt!(cx, let next_line = offset + 1;).expect("stmt4"));
- write_stmts.push(quote_stmt!(cx, buffer[offset] = $member_expr; ).expect("stm5"));
- },
- "[u8]" => {
- write_stmts.push(quote_stmt!(cx, let size = $member_expr .len();).unwrap());
- write_stmts.push(quote_stmt!(cx, let next_line = offset + size;).unwrap());
- write_stmts.push(quote_stmt!(cx, length_stack.push_back(size);).unwrap());
- write_stmts.push(quote_stmt!(cx, let $range_ident = offset..next_line; ).unwrap());
- post_write_stmts.push(quote_stmt!(cx, buffer[$range_ident].clone_from_slice($member_expr); ).unwrap());
- }
- _ => {
- write_stmts.push(quote_stmt!(cx, let next_line = offset + match $field_type_ident_qualified::len_params() {
- 0 => ::std::mem::size_of::<$field_type_ident>(),
- _ => { let size = $member_expr .size(); length_stack.push_back(size); size },
- }).unwrap());
- write_stmts.push(quote_stmt!(cx, let $range_ident = offset..next_line; ).unwrap());
- post_write_stmts.push(quote_stmt!(cx,
- if $range_ident.end - $range_ident.start > 0 {
- if let Err(e) = $member_expr .to_bytes(&mut buffer[$range_ident], length_stack) {
- return Err(e)
- };
- }
- ).unwrap());
- }
- }
-
- write_stmts.push(quote_stmt!(cx, offset = next_line; ).unwrap());
-
- let field_index = builder.id(&format!("{}", index));
- map_stmts.push(quote_stmt!(cx, map[$field_index] = total;).unwrap());
-
- match raw_ident.as_ref() {
- "u8" => {
- map_stmts.push(quote_stmt!(cx, total += 1;).unwrap());
- },
- "[u8]" => {
- map_stmts.push(quote_stmt!(cx, let size = length_stack.pop_front().unwrap();).unwrap());
- map_stmts.push(quote_stmt!(cx, total += size;).unwrap());
- },
- _ => {
- map_stmts.push(quote_stmt!(cx, let size = match $field_type_ident_qualified::len_params() {
- 0 => ::std::mem::size_of::<$field_type_ident>(),
- _ => length_stack.pop_front().unwrap(),
- }).unwrap());
- map_stmts.push(quote_stmt!(cx, total += size;).unwrap());
- }
- }
- };
-
- let read_expr = match fields.iter().any(|f| codegen::has_ptr(&f.ty)) {
- true => {
- // cannot create structs with pointers
- quote_expr!(cx, Err(::ipc::binary::BinaryConvertError::not_supported()))
- },
- false => {
- if value_ident.is_some() {
- let instance_create = named_fields_sequence(cx, &ty, fields);
- quote_expr!(cx, { $map_stmts; $instance_create; Ok(result) })
- }
- else {
- let map_variant = P(fields_sequence(cx, &ty, fields, &instance_ident.unwrap_or(builder.id("Self"))));
- quote_expr!(cx, { $map_stmts; Ok($map_variant) })
- }
- },
- };
-
- Ok(BinaryExpressions {
- size: total_size_expr,
- write: quote_expr!(cx, { $write_stmts; $post_write_stmts; Ok(()) } ),
- read: read_expr,
- })
-}
-
-#[allow(unreachable_code)]
-fn binary_expr_item_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(
- cx,
- &builder,
- ty,
- fields,
- Some(builder.id("self")),
- None,
- )
- },
- ast::VariantData::Struct(ref fields, _) => {
- binary_expr_struct(
- cx,
- &builder,
- ty,
- fields,
- Some(builder.id("self")),
- None,
- )
- },
- _ => {
- cx.span_bug(span,
- &format!("#[derive(Binary)] Unsupported struct content, expected tuple/struct, found: {:?}",
- variant_data));
- Err(Error) as Result
- },
- }
-}
-
-fn binary_expr_enum(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- type_ident: Ident,
- impl_generics: &ast::Generics,
- ty: P,
- span: Span,
- enum_def: &ast::EnumDef,
-) -> Result {
- let arms: Vec<_> = try!(enum_def.variants.iter()
- .enumerate()
- .map(|(variant_index, variant)| {
- binary_expr_variant(
- cx,
- builder,
- type_ident,
- impl_generics,
- ty.clone(),
- span,
- variant,
- variant_index,
- )
- })
- .collect());
-
- let (size_arms, write_arms, mut read_arms) = (
- arms.iter().map(|x| x.size.clone()).collect::>(),
- arms.iter().map(|x| x.write.clone()).collect::>(),
- arms.iter().map(|x| x.read.clone()).collect::>());
-
- read_arms.push(quote_arm!(cx, _ => { Err(::ipc::BinaryConvertError::variant(buffer[0])) } ));
-
- Ok(BinaryExpressions {
- size: quote_expr!(cx, 1usize + match *self { $size_arms }),
- write: quote_expr!(cx, match *self { $write_arms }; ),
- read: quote_expr!(cx, match buffer[0] { $read_arms }),
- })
-}
-
-struct BinaryArm {
- size: ast::Arm,
- write: ast::Arm,
- read: ast::Arm,
-}
-
-fn fields_sequence(
- ext_cx: &ExtCtxt,
- _ty: &P,
- fields: &[ast::StructField],
- variant_ident: &ast::Ident,
-) -> ast::Expr {
- use syntax::parse::token;
- use syntax::tokenstream::TokenTree::Token;
-
- let named_members = fields.iter().any(|f| f.ident.is_some());
-
- ::quasi::parse_expr_panic(&mut ::syntax::parse::new_parser_from_tts(
- ext_cx.parse_sess(),
- {
- let _sp = ext_cx.call_site();
- let mut tt = ::std::vec::Vec::new();
- tt.push(Token(_sp, token::Ident(variant_ident.clone())));
- if named_members {
- tt.push(Token(_sp, token::OpenDelim(token::Brace)));
- }
- else {
- tt.push(Token(_sp, token::OpenDelim(token::Paren)));
- }
-
- for (idx, field) in fields.iter().enumerate() {
- if field.ident.is_some() {
- tt.push(Token(_sp, token::Ident(field.ident.clone().unwrap())));
- tt.push(Token(_sp, token::Colon));
- }
-
- // special case for u8, it just takes byte form sequence
- if ::syntax::print::pprust::ty_to_string(&field.ty) == "u8" {
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
-
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
-
- tt.push(Token(_sp, token::Comma));
- continue;
- }
-
- // special case for [u8], it just takes a byte sequence
- if ::syntax::print::pprust::ty_to_string(&field.ty) == "[u8]" {
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
-
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
- tt.push(Token(_sp, token::DotDot));
-
- if idx+1 != fields.len() {
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
- }
-
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
-
- tt.push(Token(_sp, token::Comma));
- continue;
- }
-
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!"))));
- tt.push(Token(_sp, token::OpenDelim(token::Paren)));
- tt.push(
- Token(
- _sp,
- token::Ident(ext_cx.ident_of(&replace_qualified(&::syntax::print::pprust::ty_to_string(&field.ty))))
- ));
- tt.push(Token(_sp, token::ModSep));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("from_bytes"))));
- tt.push(Token(_sp, token::OpenDelim(token::Paren)));
-
- tt.push(Token(_sp, token::BinOp(token::And)));
-
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
-
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
- tt.push(Token(_sp, token::DotDot));
-
- if idx+1 != fields.len() {
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
- }
-
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
-
- tt.push(Token(_sp, token::Comma));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("length_stack"))));
- tt.push(Token(_sp, token::CloseDelim(token::Paren)));
-
- // name member if it has resulted in the error
- tt.push(Token(_sp, token::Dot));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map_err"))));
-
- tt.push(Token(_sp, token::OpenDelim(token::Paren)));
- tt.push(Token(_sp, token::BinOp(token::Or)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("e"))));
- tt.push(Token(_sp, token::BinOp(token::Or)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("e"))));
- tt.push(Token(_sp, token::Dot));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("named"))));
- tt.push(Token(_sp, token::OpenDelim(token::Paren)));
- tt.push(Token(_sp, token::Literal(token::Lit::Str_(
- field.ident.unwrap_or(ext_cx.ident_of(&format!("f{}", idx))).name),
- None))
- );
- tt.push(Token(_sp, token::CloseDelim(token::Paren)));
- tt.push(Token(_sp, token::CloseDelim(token::Paren)));
-
- tt.push(Token(_sp, token::CloseDelim(token::Paren)));
-
- tt.push(Token(_sp, token::Comma));
- }
- if named_members {
- tt.push(Token(_sp, token::CloseDelim(token::Brace)));
- }
- else {
- tt.push(Token(_sp, token::CloseDelim(token::Paren)));
- }
- tt
- })
- ).unwrap()
-}
-
-fn named_fields_sequence(
- ext_cx: &ExtCtxt,
- ty: &P,
- fields: &[ast::StructField],
-) -> ast::Stmt {
- use syntax::parse::token;
- use syntax::tokenstream::TokenTree::Token;
-
- ::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts(
- ext_cx.parse_sess(),
- {
- let _sp = ext_cx.call_site();
- let mut tt = ::std::vec::Vec::new();
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("let"))));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("result"))));
- tt.push(Token(_sp, token::Eq));
-
- tt.push(Token(
- _sp,
- token::Ident(
- ext_cx.ident_of(&::syntax::print::pprust::ty_to_string(ty))
- )));
-
- tt.push(Token(_sp, token::OpenDelim(token::Brace)));
-
- for (idx, field) in fields.iter().enumerate() {
- tt.push(Token(_sp, match field.ident {
- Some(ident) => token::Ident(ident),
- None => token::Ident(ext_cx.ident_of(&format!("{}", idx))),
- }));
- tt.push(Token(_sp, token::Colon));
-
- // special case for u8, it just takes byte form sequence
- if ::syntax::print::pprust::ty_to_string(&field.ty) == "u8" {
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
-
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
-
- tt.push(Token(_sp, token::Comma));
- continue;
- }
-
- // special case for [u8], it just takes a byte sequence
- if ::syntax::print::pprust::ty_to_string(&field.ty) == "[u8]" {
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
-
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
- tt.push(Token(_sp, token::DotDot));
-
- if idx+1 != fields.len() {
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
- }
-
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
-
- tt.push(Token(_sp, token::Comma));
- continue;
- }
-
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("try!"))));
- tt.push(Token(_sp, token::OpenDelim(token::Paren)));
- tt.push(Token(
- _sp,
- token::Ident(
- ext_cx.ident_of(&replace_qualified(&::syntax::print::pprust::ty_to_string(&field.ty)))
- )));
- tt.push(Token(_sp, token::ModSep));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("from_bytes"))));
- tt.push(Token(_sp, token::OpenDelim(token::Paren)));
-
- tt.push(Token(_sp, token::BinOp(token::And)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("buffer"))));
-
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx)))));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
- tt.push(Token(_sp, token::DotDot));
- if idx + 1 != fields.len() {
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map"))));
- tt.push(Token(_sp, token::OpenDelim(token::Bracket)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of(&format!("{}", idx+1)))));
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
- }
-
- tt.push(Token(_sp, token::CloseDelim(token::Bracket)));
-
- tt.push(Token(_sp, token::Comma));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("length_stack"))));
- tt.push(Token(_sp, token::CloseDelim(token::Paren)));
-
- // name member if it has resulted in the error
- tt.push(Token(_sp, token::Dot));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("map_err"))));
- tt.push(Token(_sp, token::OpenDelim(token::Paren)));
- tt.push(Token(_sp, token::BinOp(token::Or)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("e"))));
- tt.push(Token(_sp, token::BinOp(token::Or)));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("e"))));
- tt.push(Token(_sp, token::Dot));
- tt.push(Token(_sp, token::Ident(ext_cx.ident_of("named"))));
- tt.push(Token(_sp, token::OpenDelim(token::Paren)));
- tt.push(Token(_sp, token::Literal(token::Lit::Str_(
- field.ident.unwrap_or(ext_cx.ident_of(&format!("f{}", idx))).name),
- None))
- );
- tt.push(Token(_sp, token::CloseDelim(token::Paren)));
- tt.push(Token(_sp, token::CloseDelim(token::Paren)));
-
- tt.push(Token(_sp, token::CloseDelim(token::Paren)));
- tt.push(Token(_sp, token::Comma));
- }
-
- tt.push(Token(_sp, token::CloseDelim(token::Brace)));
- tt
- })
- ).unwrap()
-}
-
-fn binary_expr_variant(
- cx: &ExtCtxt,
- builder: &aster::AstBuilder,
- type_ident: Ident,
- _generics: &ast::Generics,
- ty: P,
- _span: Span,
- variant: &ast::Variant,
- variant_index: usize,
-) -> Result {
- let variant_ident = variant.node.name;
- let variant_index_ident = builder.id(format!("{}", variant_index));
-
- match variant.node.data {
- ast::VariantData::Unit(_) => {
- let pat = builder.pat().path()
- .id(type_ident).id(variant_ident)
- .build();
-
- let variant_val = builder.id(format!("{}::{}", type_ident, variant_ident));
-
- Ok(BinaryArm {
- size: quote_arm!(cx, $pat => { 0usize } ),
- write: quote_arm!(cx, $pat => { buffer[0] = $variant_index_ident; Ok(()) } ),
- read: quote_arm!(cx, $variant_index_ident => { Ok($variant_val) } ),
- })
- },
- ast::VariantData::Tuple(ref fields, _) => {
- let field_names: Vec = (0 .. fields.len())
- .map(|i| builder.id(format!("__field{}", i)))
- .collect();
-
- let pat = builder.pat().enum_()
- .id(type_ident).id(variant_ident).build()
- .with_pats(
- field_names.iter()
- .map(|field| builder.pat().ref_id(field))
- )
- .build();
-
- let binary_expr = try!(binary_expr_struct(
- cx,
- &builder,
- ty,
- fields,
- None,
- Some(builder.id(format!("{}::{}", type_ident, variant_ident))),
- ));
-
- let (size_expr, write_expr, read_expr) = (binary_expr.size, vec![binary_expr.write], binary_expr.read);
- Ok(BinaryArm {
- size: quote_arm!(cx, $pat => { $size_expr } ),
- write: quote_arm!(cx,
- $pat => {
- buffer[0] = $variant_index_ident;
- let buffer = &mut buffer[1..];
- $write_expr
- }),
- read: quote_arm!(cx,
- $variant_index_ident => {
- let buffer = &buffer[1..];
- $read_expr
- }
- ),
- })
- },
- ast::VariantData::Struct(ref fields, _) => {
- let field_names: Vec<_> = (0 .. fields.len())
- .map(|i| builder.id(format!("__field{}", i)))
- .collect();
-
- let pat = builder.pat().struct_()
- .id(type_ident).id(variant_ident).build()
- .with_pats(
- field_names.iter()
- .zip(fields.iter())
- .map(|(id, field)|(field.ident.unwrap(), builder.pat().ref_id(id))))
- .build();
-
- let binary_expr = try!(binary_expr_struct(
- cx,
- &builder,
- ty,
- fields,
- None,
- Some(builder.id(format!("{}::{}", type_ident, variant_ident))),
- ));
-
- let (size_expr, write_expr, read_expr) = (binary_expr.size, vec![binary_expr.write], binary_expr.read);
-
- Ok(BinaryArm {
- size: quote_arm!(cx, $pat => { $size_expr } ),
- write: quote_arm!(cx,
- $pat => {
- buffer[0] = $variant_index_ident;
- let buffer = &mut buffer[1..];
- $write_expr
- }),
- read: quote_arm!(cx,
- $variant_index_ident => {
- let buffer = &buffer[1..];
- $read_expr
- }
- ),
- })
- },
- }
-}
diff --git a/ipc/hypervisor/Cargo.toml b/ipc/hypervisor/Cargo.toml
deleted file mode 100644
index 1db60c904..000000000
--- a/ipc/hypervisor/Cargo.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[package]
-name = "ethcore-ipc-hypervisor"
-version = "1.2.0"
-authors = ["Parity Technologies "]
-license = "GPL-3.0"
-build = "build.rs"
-
-[features]
-
-[dependencies]
-ethcore-ipc = { path = "../rpc" }
-nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git", branch = "parity-1.7" }
-ethcore-ipc-nano = { path = "../nano" }
-semver = "0.6"
-log = "0.3"
-time = "0.1"
-
-[build-dependencies]
-ethcore-ipc-codegen = { path = "../codegen" }
diff --git a/ipc/hypervisor/build.rs b/ipc/hypervisor/build.rs
deleted file mode 100644
index 097aba046..000000000
--- a/ipc/hypervisor/build.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2015-2017 Parity Technologies (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 ethcore_ipc_codegen;
-
-fn main() {
- ethcore_ipc_codegen::derive_ipc("src/service.rs.in").unwrap();
-}
diff --git a/ipc/hypervisor/src/lib.rs b/ipc/hypervisor/src/lib.rs
deleted file mode 100644
index b522122b5..000000000
--- a/ipc/hypervisor/src/lib.rs
+++ /dev/null
@@ -1,273 +0,0 @@
-// Copyright 2015-2017 Parity Technologies (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 .
-
-//! Parity interprocess hypervisor module
-
-#![cfg_attr(feature="dev", allow(used_underscore_binding))]
-
-extern crate ethcore_ipc as ipc;
-extern crate ethcore_ipc_nano as nanoipc;
-extern crate semver;
-#[macro_use] extern crate log;
-extern crate time;
-
-pub mod service;
-
-/// Default value for hypervisor ipc listener
-pub const HYPERVISOR_IPC_URL: &'static str = "parity-internal-hyper-status.ipc";
-
-use std::sync::{Arc,RwLock};
-use service::{HypervisorService, IpcModuleId};
-use std::process::{Command,Child};
-use std::collections::HashMap;
-
-pub use service::{HypervisorServiceClient, ControlService, CLIENT_MODULE_ID, SYNC_MODULE_ID};
-
-pub type BinaryId = &'static str;
-
-pub struct Hypervisor {
- ipc_addr: String,
- service: Arc,
- ipc_worker: RwLock>,
- processes: RwLock>,
- modules: HashMap,
- pub io_path: String,
-}
-
-/// Boot arguments for binary
-pub struct BootArgs {
- cli: Option>,
- stdin: Option>,
-}
-
-impl BootArgs {
- /// New empty boot arguments
- pub fn new() -> BootArgs {
- BootArgs {
- cli: None,
- stdin: None,
- }
- }
-
- /// Set command-line arguments for boot
- pub fn cli(mut self, cli: Vec) -> BootArgs {
- self.cli = Some(cli);
- self
- }
-
- /// Set std-in stream for boot
- pub fn stdin(mut self, stdin: Vec) -> BootArgs {
- self.stdin = Some(stdin);
- self
- }
-}
-
-impl Hypervisor {
- /// initializes the Hypervisor service with the open ipc socket for incoming clients
- pub fn new() -> Hypervisor {
- Hypervisor::with_url(HYPERVISOR_IPC_URL)
- }
-
- pub fn module(mut self, module_id: IpcModuleId, args: BootArgs) -> Hypervisor {
- self.modules.insert(module_id, args);
- self.service.add_module(module_id);
- self
- }
-
- pub fn local_module(self, module_id: IpcModuleId) -> Hypervisor {
- self.service.add_module(module_id);
- self
- }
-
- pub fn io_path(mut self, directory: &str) -> Hypervisor {
- self.io_path = directory.to_owned();
- self
- }
-
- /// Starts with the specified address for the ipc listener and
- /// the specified list of modules in form of created service
- pub fn with_url(addr: &str) -> Hypervisor {
- let service = HypervisorService::new();
- let worker = nanoipc::Worker::new(&service);
- Hypervisor{
- ipc_addr: addr.to_owned(),
- service: service,
- ipc_worker: RwLock::new(worker),
- processes: RwLock::new(HashMap::new()),
- modules: HashMap::new(),
- io_path: "/tmp".to_owned(),
- }
- }
-
- /// Since one binary can host multiple modules
- /// we match binaries
- fn match_module(&self, module_id: &IpcModuleId) -> Option<&BootArgs> {
- self.modules.get(module_id)
- }
-
- /// Creates IPC listener and starts all binaries
- pub fn start(&self) {
- let mut worker = self.ipc_worker.write().unwrap();
- worker.add_reqrep(&self.ipc_addr).unwrap_or_else(|e| panic!("Hypervisor ipc worker can not start - critical! ({:?})", e));
-
- for module_id in self.service.module_ids() {
- self.start_module(module_id);
- }
- }
-
- /// Start binary for the specified module
- /// Does nothing when it is already started on module is inside the
- /// main binary
- fn start_module(&self, module_id: IpcModuleId) {
- use std::io::Write;
-
- self.match_module(&module_id).map(|boot_args| {
- let mut processes = self.processes.write().unwrap();
- {
- if processes.get(&module_id).is_some() {
- // already started for another module
- return;
- }
- }
-
- let mut command = Command::new(&std::env::current_exe().unwrap());
- command.stderr(std::process::Stdio::inherit());
-
- if let Some(ref cli_args) = boot_args.cli {
- for arg in cli_args { command.arg(arg); }
- }
-
- command.stdin(std::process::Stdio::piped());
-
- trace!(target: "hypervisor", "Spawn executable: {:?}", command);
-
- let mut child = command.spawn().unwrap_or_else(
- |e| panic!("Hypervisor cannot execute command ({:?}): {}", command, e));
-
- if let Some(ref std_in) = boot_args.stdin {
- trace!(target: "hypervisor", "Pushing std-in payload...");
- child.stdin.as_mut()
- .expect("std-in should be piped above")
- .write(std_in)
- .unwrap_or_else(|e| panic!(format!("Error trying to pipe stdin for {:?}: {:?}", &command, e)));
- drop(child.stdin.take());
- }
-
- processes.insert(module_id, child);
- });
- }
-
- /// Reports if all modules are checked in
- pub fn modules_ready(&self) -> bool {
- self.service.unchecked_count() == 0
- }
-
- pub fn modules_shutdown(&self) -> bool {
- self.service.running_count() == 0
- }
-
- /// Waits for every required module to check in
- pub fn wait_for_startup(&self) {
- let mut worker = self.ipc_worker.write().unwrap();
- while !self.modules_ready() {
- worker.poll()
- }
- }
-
- /// Waits for every required module to check in
- pub fn wait_for_shutdown(&self) -> bool {
- use time::{PreciseTime, Duration};
-
- let mut worker = self.ipc_worker.write().unwrap();
- let start = PreciseTime::now();
- while !self.modules_shutdown() {
- worker.poll();
- if start.to(PreciseTime::now()) > Duration::seconds(30) {
- warn!("Some modules failed to shutdown gracefully, they will be terminated.");
- break;
- }
- }
- self.modules_shutdown()
- }
-
- /// Shutdown the ipc and all managed child processes
- pub fn shutdown(&self) {
- let mut childs = self.processes.write().unwrap();
- for (ref module, _) in childs.iter() {
- trace!(target: "hypervisor", "Stopping process module: {}", module);
- self.service.send_shutdown(**module);
- }
- trace!(target: "hypervisor", "Waiting for shutdown...");
- if self.wait_for_shutdown() {
- trace!(target: "hypervisor", "All modules reported shutdown");
- return;
- }
-
- for (ref module, ref mut process) in childs.iter_mut() {
- if self.service.is_running(**module) {
- process.kill().unwrap();
- trace!("Terminated {}", module);
- }
- }
- }
-}
-
-impl Drop for Hypervisor {
- fn drop(&mut self) {
- self.shutdown();
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use std::sync::atomic::{AtomicBool,Ordering};
- use std::sync::Arc;
- use nanoipc;
-
- #[test]
- fn can_init() {
- let url = "ipc:///tmp/test-parity-hypervisor-10.ipc";
- let test_module_id = 8080u64;
-
- let hypervisor = Hypervisor::with_url(url).local_module(test_module_id);
- assert_eq!(false, hypervisor.modules_ready());
- }
-
- #[test]
- fn can_wait_for_startup() {
- let url = "ipc:///tmp/test-parity-hypervisor-20.ipc";
- let test_module_id = 8080u64;
-
- let hypervisor_ready = Arc::new(AtomicBool::new(false));
- let hypervisor_ready_local = hypervisor_ready.clone();
-
- ::std::thread::spawn(move || {
- while !hypervisor_ready.load(Ordering::Relaxed) { }
-
- let client = nanoipc::fast_client::>(url).unwrap();
- client.handshake().unwrap();
- client.module_ready(test_module_id, url.to_owned());
- });
-
- let hypervisor = Hypervisor::with_url(url).local_module(test_module_id);
- hypervisor.start();
- hypervisor_ready_local.store(true, Ordering::Relaxed);
- hypervisor.wait_for_startup();
-
- assert_eq!(true, hypervisor.modules_ready());
- }
-}
diff --git a/ipc/hypervisor/src/service.rs b/ipc/hypervisor/src/service.rs
deleted file mode 100644
index 59040251e..000000000
--- a/ipc/hypervisor/src/service.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015-2017 Parity Technologies (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 .
-
-//! Parity interprocess hypervisor IPC service
-#![allow(dead_code, unused_assignments, unused_variables)] // codegen issues
-
-include!(concat!(env!("OUT_DIR"), "/service.rs.in"));
diff --git a/ipc/hypervisor/src/service.rs.in b/ipc/hypervisor/src/service.rs.in
deleted file mode 100644
index 6d6f38268..000000000
--- a/ipc/hypervisor/src/service.rs.in
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2015-2017 Parity Technologies (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 std::sync::{RwLock,Arc};
-use ipc::IpcConfig;
-use std::collections::HashMap;
-use nanoipc;
-
-pub type IpcModuleId = u64;
-
-/// Blockhain database module id
-pub const CLIENT_MODULE_ID: IpcModuleId = 2000;
-
-/// Sync module id
-pub const SYNC_MODULE_ID: IpcModuleId = 2100;
-
-/// IPC service that handles module management
-pub struct HypervisorService {
- modules: RwLock>,
-}
-
-#[derive(Default)]
-pub struct ModuleState {
- started: bool,
- control_url: String,
- shutdown: bool,
-}
-
-#[ipc]
-pub trait ControlService {
- fn shutdown(&self) -> bool;
-}
-
-#[ipc]
-impl HypervisorService {
- // return type for making method synchronous
- fn module_ready(&self, module_id: u64, control_url: String) -> bool {
- let mut modules = self.modules.write().unwrap();
- modules.get_mut(&module_id).map(|mut module| {
- module.started = true;
- module.control_url = control_url;
- });
- trace!(target: "hypervisor", "Module ready: {}", module_id);
- true
- }
-
- // return type for making method synchronous
- fn module_shutdown(&self, module_id: u64) -> bool {
- let mut modules = self.modules.write().unwrap();
- modules.get_mut(&module_id).map(|mut module| {
- module.shutdown = true;
- });
- trace!(target: "hypervisor", "Module shutdown: {}", module_id);
- true
- }
-}
-
-impl HypervisorService {
- /// New service with the default list of modules
- pub fn new() -> Arc {
- HypervisorService::with_modules(vec![])
- }
-
- /// New service with list of modules that will report for being ready
- pub fn with_modules(module_ids: Vec) -> Arc {
- let mut modules = HashMap::new();
- for module_id in module_ids {
- modules.insert(module_id, ModuleState::default());
- }
- Arc::new(HypervisorService {
- modules: RwLock::new(modules),
- })
- }
-
- /// Add the module to the check-list
- pub fn add_module(&self, module_id: IpcModuleId) {
- self.modules.write().unwrap().insert(module_id, ModuleState::default());
- }
-
- /// Number of modules still being waited for check-in
- pub fn unchecked_count(&self) -> usize {
- self.modules.read().unwrap().iter().filter(|&(_, module)| !module.started).count()
- }
-
- /// List of all modules within this service
- pub fn module_ids(&self) -> Vec {
- self.modules.read().unwrap().iter().map(|(module_id, _)| module_id).cloned().collect()
- }
-
- /// Number of modules started and running
- pub fn running_count(&self) -> usize {
- self.modules.read().unwrap().iter().filter(|&(_, module)| module.started && !module.shutdown).count()
- }
-
- pub fn is_running(&self, id: IpcModuleId) -> bool {
- self.modules.read().unwrap().get(&id).map(|module| module.started && !module.shutdown).unwrap_or(false)
- }
-
- pub fn send_shutdown(&self, module_id: IpcModuleId) {
- let modules = self.modules.read().unwrap();
- modules.get(&module_id).map(|module| {
- trace!(target: "hypervisor", "Sending shutdown to {}({})", module_id, &module.control_url);
- let client = nanoipc::fast_client::>(&module.control_url).unwrap();
- client.shutdown();
- trace!(target: "hypervisor", "Sent shutdown to {}", module_id);
- });
- }
-}
-
-impl ::ipc::IpcConfig for HypervisorService {}
-
-impl ::ipc::IpcConfig for ControlService {}
diff --git a/ipc/nano/Cargo.toml b/ipc/nano/Cargo.toml
deleted file mode 100644
index a714e1d00..000000000
--- a/ipc/nano/Cargo.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-[package]
-name = "ethcore-ipc-nano"
-version = "1.8.0"
-authors = ["Parity Technologies "]
-license = "GPL-3.0"
-
-[features]
-
-[dependencies]
-ethcore-ipc = { path = "../rpc" }
-nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git", branch = "parity-1.7" }
-log = "0.3"
-lazy_static = "0.2"
diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs
deleted file mode 100644
index 9be3d2b1d..000000000
--- a/ipc/nano/src/lib.rs
+++ /dev/null
@@ -1,355 +0,0 @@
-// Copyright 2015-2017 Parity Technologies (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 .
-
-//! IPC over nanomsg transport
-
-extern crate ethcore_ipc as ipc;
-extern crate nanomsg;
-#[macro_use] extern crate log;
-#[macro_use] extern crate lazy_static;
-
-pub use ipc::{WithSocket, IpcInterface, IpcConfig};
-pub use nanomsg::Socket as NanoSocket;
-
-use std::sync::*;
-use nanomsg::{Socket, Protocol, Error, Endpoint, PollRequest, PollFd, PollInOut};
-use std::ops::Deref;
-
-const POLL_TIMEOUT: isize = 200;
-const DEFAULT_CONNECTION_TIMEOUT: isize = 30000;
-const DEBUG_CONNECTION_TIMEOUT: isize = 5000;
-
-/// Generic worker to handle service (binded) sockets
-pub struct Worker where S: IpcInterface {
- service: Arc,
- sockets: Vec<(Socket, Endpoint)>,
- polls: Vec,
- buf: Vec,
-}
-
-/// struct for guarding `_endpoint` (so that it wont drop)
-/// derefs to client `S`
-pub struct GuardedSocket where S: WithSocket {
- client: Arc,
- _endpoint: Endpoint,
-}
-
-impl GuardedSocket where S: WithSocket {
- pub fn service(&self) -> Arc {
- self.client.clone()
- }
-}
-
-impl Deref for GuardedSocket where S: WithSocket {
- type Target = Arc;
-
- fn deref(&self) -> &Arc {
- &self.client
- }
-}
-
-/// Spawns client <`S`> over specified address
-/// creates socket and connects endpoint to it
-/// for duplex (paired) connections with the service
-pub fn init_duplex_client(socket_addr: &str) -> Result, SocketError> where S: WithSocket {
- let mut socket = Socket::new(Protocol::Pair).map_err(|e| {
- warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
- SocketError::DuplexLink
- })?;
-
- socket.set_receive_timeout(DEFAULT_CONNECTION_TIMEOUT).unwrap();
-
- let endpoint = socket.connect(socket_addr).map_err(|e| {
- warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", socket_addr, e);
- SocketError::DuplexLink
- })?;
-
- Ok(GuardedSocket {
- client: Arc::new(S::init(socket)),
- _endpoint: endpoint,
- })
-}
-
-/// Spawns client <`S`> over specified address
-/// creates socket and connects endpoint to it
-/// for request-reply connections to the service
-pub fn client(socket_addr: &str, receive_timeout: Option) -> Result, SocketError> where S: WithSocket {
- let mut socket = Socket::new(Protocol::Req).map_err(|e| {
- warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
- SocketError::RequestLink
- })?;
-
- if let Some(timeout) = receive_timeout {
- socket.set_receive_timeout(timeout).unwrap();
- }
-
- let endpoint = socket.connect(socket_addr).map_err(|e| {
- warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", socket_addr, e);
- SocketError::RequestLink
- })?;
-
- trace!(target: "ipc", "Created client for {}", socket_addr);
- Ok(GuardedSocket {
- client: Arc::new(S::init(socket)),
- _endpoint: endpoint,
- })
-}
-
-lazy_static! {
- /// Set PARITY_IPC_DEBUG=1 for fail-fast connectivity problems diagnostic
- pub static ref DEBUG_FLAG: bool = {
- use std::env;
-
- if let Ok(debug) = env::var("PARITY_IPC_DEBUG") {
- debug == "1" || debug.to_uppercase() == "TRUE"
- }
- else { false }
- };
-}
-
-/// Client with no default timeout on operations
-pub fn generic_client(socket_addr: &str) -> Result, SocketError> where S: WithSocket {
- if *DEBUG_FLAG {
- client(socket_addr, Some(DEBUG_CONNECTION_TIMEOUT))
- } else {
- client(socket_addr, None)
- }
-}
-
-/// Client over interface that is supposed to give quick almost non-blocking responses
-pub fn fast_client(socket_addr: &str) -> Result, SocketError> where S: WithSocket {
- if *DEBUG_FLAG {
- client(socket_addr, Some(DEBUG_CONNECTION_TIMEOUT))
- } else {
- client(socket_addr, Some(DEFAULT_CONNECTION_TIMEOUT))
- }
-}
-
-/// Error occurred while establising socket or endpoint
-#[derive(Debug)]
-pub enum SocketError {
- /// Error establising duplex (paired) socket and/or endpoint
- DuplexLink,
- /// Error establising duplex (paired) socket and/or endpoint
- RequestLink,
-}
-
-impl Worker where S: IpcInterface {
- /// New worker over specified `service`
- pub fn new(service: &Arc) -> Worker {
- Worker:: {
- service: service.clone(),
- sockets: Vec::new(),
- polls: Vec::new(),
- buf: Vec::new(),
- }
- }
-
- /// Polls all sockets, reads and dispatches method invocations
- pub fn poll(&mut self) {
- use std::io::Write;
-
- let mut request = PollRequest::new(&mut self.polls[..]);
- let _result_guard = Socket::poll(&mut request, POLL_TIMEOUT);
-
- for (fd_index, fd) in request.get_fds().iter().enumerate() {
- if fd.can_read() {
- let (ref mut socket, _) = self.sockets[fd_index];
- unsafe { self.buf.set_len(0); }
- match socket.nb_read_to_end(&mut self.buf) {
- Ok(method_sign_len) => {
- if method_sign_len >= 2 {
-
- // method_num
- let method_num = self.buf[0] as u16 * 256 + self.buf[1] as u16;
- // payload
- let payload = &self.buf[2..];
-
- // dispatching for ipc interface
- let result = self.service.dispatch_buf(method_num, payload);
-
- if let Err(e) = socket.write(&result) {
- warn!(target: "ipc", "Failed to write response: {:?}", e);
- }
- }
- else {
- warn!(target: "ipc", "Failed to read method signature from socket: unexpected message length({})", method_sign_len);
- }
- },
- Err(Error::TryAgain) => {
- },
- Err(x) => {
- warn!(target: "ipc", "Error polling connections {:?}", x);
- panic!();
- }
- }
- }
- }
- }
-
- /// Stores nanomsg poll request for reuse
- fn rebuild_poll_request(&mut self) {
- self.polls = self.sockets.iter()
- .map(|&(ref socket, _)| socket.new_pollfd(PollInOut::In))
- .collect::>();
- }
-
- /// Add exclusive socket for paired client
- /// Only one connection over this address is allowed
- pub fn add_duplex(&mut self, addr: &str) -> Result<(), SocketError> {
- let mut socket = Socket::new(Protocol::Pair).map_err(|e| {
- warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
- SocketError::DuplexLink
- })?;
-
- let endpoint = socket.bind(addr).map_err(|e| {
- warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", addr, e);
- SocketError::DuplexLink
- })?;
-
- self.sockets.push((socket, endpoint));
-
- self.rebuild_poll_request();
-
- trace!(target: "ipc", "Started duplex worker at {}", addr);
-
- Ok(())
- }
-
- /// Add generic socket for request-reply style communications
- /// with multiple clients
- pub fn add_reqrep(&mut self, addr: &str) -> Result<(), SocketError> {
- let mut socket = Socket::new(Protocol::Rep).map_err(|e| {
- warn!(target: "ipc", "Failed to create ipc socket: {:?}", e);
- SocketError::DuplexLink
- })?;
-
-
- let endpoint = socket.bind(addr).map_err(|e| {
- warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", addr, e);
- SocketError::DuplexLink
- })?;
-
- self.sockets.push((socket, endpoint));
-
- self.rebuild_poll_request();
-
- trace!(target: "ipc", "Started request-reply worker at {}", addr);
- Ok(())
- }
-}
-
-#[cfg(test)]
-mod service_tests {
-
- use super::Worker;
- use ipc::*;
- use std::io::{Read, Write};
- use std::sync::{Arc, RwLock};
- use nanomsg::{Socket, Protocol, Endpoint};
-
- struct TestInvoke {
- method_num: u16,
- params: Vec,
- }
-
- struct DummyService {
- methods_stack: RwLock>,
- }
-
- impl DummyService {
- fn new() -> DummyService {
- DummyService { methods_stack: RwLock::new(Vec::new()) }
- }
- }
-
- impl IpcInterface for DummyService {
- fn dispatch(&self, _r: &mut R) -> Vec where R: Read {
- vec![]
- }
- fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec {
- self.methods_stack.write().unwrap().push(
- TestInvoke {
- method_num: method_num,
- params: buf.to_vec(),
- });
- vec![]
- }
- }
-
- impl IpcConfig for DummyService {}
-
- fn dummy_write(addr: &str, buf: &[u8]) -> (Socket, Endpoint) {
- let mut socket = Socket::new(Protocol::Pair).unwrap();
- let endpoint = socket.connect(addr).unwrap();
- socket.write(buf).unwrap();
- (socket, endpoint)
- }
-
- #[test]
- fn can_create_worker() {
- let worker = Worker::::new(&Arc::new(DummyService::new()));
- assert_eq!(0, worker.sockets.len());
- }
-
- #[test]
- fn can_add_duplex_socket_to_worker() {
- let mut worker = Worker::::new(&Arc::new(DummyService::new()));
- worker.add_duplex("ipc:///tmp/parity-test10.ipc").unwrap();
- assert_eq!(1, worker.sockets.len());
- }
-
- #[test]
- fn worker_can_poll_empty() {
- let service = Arc::new(DummyService::new());
- let mut worker = Worker::::new(&service);
- worker.add_duplex("ipc:///tmp/parity-test20.ipc").unwrap();
- worker.poll();
- assert_eq!(0, service.methods_stack.read().unwrap().len());
- }
-
- #[test]
- fn worker_can_poll() {
- let url = "ipc:///tmp/parity-test30.ipc";
-
- let mut worker = Worker::::new(&Arc::new(DummyService::new()));
- worker.add_duplex(url).unwrap();
-
- let (_socket, _endpoint) = dummy_write(url, &vec![0, 0, 7, 7, 6, 6]);
- worker.poll();
-
- assert_eq!(1, worker.service.methods_stack.read().unwrap().len());
- assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num);
- assert_eq!([7, 7, 6, 6], worker.service.methods_stack.read().unwrap()[0].params[..]);
- }
-
- #[test]
- fn worker_can_poll_long() {
- let url = "ipc:///tmp/parity-test40.ipc";
-
- let mut worker = Worker::::new(&Arc::new(DummyService::new()));
- worker.add_duplex(url).unwrap();
-
- let message = [0u8; 1024*1024];
-
- let (_socket, _endpoint) = dummy_write(url, &message);
- worker.poll();
-
- assert_eq!(1, worker.service.methods_stack.read().unwrap().len());
- assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num);
- assert_eq!(vec![0u8; 1024*1024-2], worker.service.methods_stack.read().unwrap()[0].params);
- }
-}
diff --git a/ipc/rpc/Cargo.toml b/ipc/rpc/Cargo.toml
deleted file mode 100644
index 12d73a118..000000000
--- a/ipc/rpc/Cargo.toml
+++ /dev/null
@@ -1,14 +0,0 @@
-[package]
-name = "ethcore-ipc"
-version = "1.8.0"
-authors = ["Parity Technologies "]
-license = "GPL-3.0"
-
-[features]
-
-[dependencies]
-ethcore-devtools = { path = "../../devtools" }
-nanomsg = { git = "https://github.com/paritytech/nanomsg.rs.git", branch = "parity-1.7" }
-ethcore-bigint = { path = "../../util/bigint"}
-ethcore-util = { path = "../../util" }
-semver = "0.6"
diff --git a/ipc/rpc/src/binary.rs b/ipc/rpc/src/binary.rs
deleted file mode 100644
index 6466acdb1..000000000
--- a/ipc/rpc/src/binary.rs
+++ /dev/null
@@ -1,1196 +0,0 @@
-// Copyright 2015-2017 Parity Technologies (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
-
-use bigint::prelude::{U256, U512};
-use bigint::hash::{H256, H512, H2048};
-use util::{Address};
-use std::mem;
-use std::collections::{VecDeque, BTreeMap};
-use std::ops::Range;
-use super::Handshake;
-
-#[derive(Debug)]
-pub enum BinaryConvertErrorKind {
- SizeMismatch {
- expected: usize,
- found: usize,
- },
- TargetPayloadEmpty,
- UnexpectedVariant(u8),
- MissingLengthValue,
- InconsistentBoundaries,
- NotSupported,
-}
-
-#[derive(Debug)]
-pub struct BinaryConvertError {
- member_tree: Vec<&'static str>,
- kind: BinaryConvertErrorKind,
-}
-
-impl BinaryConvertError {
- pub fn size(expected: usize, found: usize) -> BinaryConvertError {
- BinaryConvertError {
- member_tree: Vec::new(),
- kind: BinaryConvertErrorKind::SizeMismatch {
- expected: expected,
- found: found,
- }
- }
- }
-
- pub fn empty() -> BinaryConvertError {
- BinaryConvertError { member_tree: Vec::new(), kind: BinaryConvertErrorKind::TargetPayloadEmpty }
- }
-
- pub fn variant(val: u8) -> BinaryConvertError {
- BinaryConvertError { member_tree: Vec::new(), kind: BinaryConvertErrorKind::UnexpectedVariant(val) }
- }
-
- pub fn length() -> BinaryConvertError {
- BinaryConvertError { member_tree: Vec::new(), kind: BinaryConvertErrorKind::MissingLengthValue }
- }
-
- pub fn boundaries() -> BinaryConvertError {
- BinaryConvertError { member_tree: Vec::new(), kind: BinaryConvertErrorKind::InconsistentBoundaries }
- }
-
- pub fn not_supported() -> BinaryConvertError {
- BinaryConvertError { member_tree: Vec::new(), kind: BinaryConvertErrorKind::NotSupported }
- }
-
- pub fn named(mut self, name: &'static str) -> BinaryConvertError {
- self.member_tree.push(name);
- self
- }
-}
-
-#[derive(Debug)]
-pub enum BinaryError {
- Serialization(BinaryConvertError),
- Io(::std::io::Error),
-}
-
-impl From<::std::io::Error> for BinaryError {
- fn from(err: ::std::io::Error) -> Self { BinaryError::Io(err) }
-}
-
-impl From for BinaryError {
- fn from(err: BinaryConvertError) -> Self { BinaryError::Serialization(err) }
-}
-
-pub trait BinaryConvertable : Sized {
- fn size(&self) -> usize {
- mem::size_of::()
- }
-
- fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError>;
-
- fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result;
-
- fn from_empty_bytes() -> Result {
- Err(BinaryConvertError::size(mem::size_of::(), 0))
- }
-
- fn len_params() -> usize {
- 0
- }
-}
-
-impl BinaryConvertable for Option where T: BinaryConvertable {
- fn size(&self) -> usize {
- match * self { None => 0, Some(ref val) => val.size() }
- }
-
- fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> {
- match *self { None => Err(BinaryConvertError::empty()), Some(ref val) => val.to_bytes(buffer, length_stack) }
- }
-
- fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result {
- if buffer.len() == 0 { return Self::from_empty_bytes(); }
- Ok(Some(T::from_bytes(buffer, length_stack)?))
- }
-
- fn from_empty_bytes() -> Result {
- Ok(None)
- }
-
- fn len_params() -> usize {
- 1
- }
-}
-
-impl BinaryConvertable for Result<(), E> {
- fn size(&self) -> usize {
- match *self {
- Ok(_) => 0,
- Err(ref e) => e.size(),
- }
- }
-
- fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> {
- match *self {
- Ok(_) => Err(BinaryConvertError::empty()),
- Err(ref e) => Ok(e.to_bytes(buffer, length_stack)?),
- }
- }
-
- fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result {
- Ok(Err(E::from_bytes(&buffer, length_stack)?))
- }
-
- fn from_empty_bytes() -> Result {
- Ok(Ok(()))
- }
-
- fn len_params() -> usize {
- 1
- }
-}
-
-
-impl BinaryConvertable for Result {
- fn size(&self) -> usize {
- match *self {
- Ok(ref r) => r.size(),
- Err(_) => 0,
- }
- }
-
- fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> {
- match *self {
- Ok(ref r) => Ok(r.to_bytes(buffer, length_stack)?),
- Err(_) => Err(BinaryConvertError::empty()),
- }
- }
-
- fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result {
- Ok(Ok(R::from_bytes(&buffer, length_stack)?))
- }
-
- fn from_empty_bytes() -> Result {
- Ok(Err(()))
- }
-
- fn len_params() -> usize {
- 1
- }
-}
-
-impl BinaryConvertable for Result {
- fn size(&self) -> usize {
- 1usize + match *self {
- Ok(ref r) => r.size(),
- Err(ref e) => e.size(),
- }
- }
-
- fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> {
- match *self {
- Ok(ref r) => {
- buffer[0] = 0;
- if r.size() > 0 {
- Ok(r.to_bytes(&mut buffer[1..], length_stack)?)
- }
- else { Ok(()) }
- },
- Err(ref e) => {
- buffer[0] = 1;
- if e.size() > 0 {
- Ok(e.to_bytes(&mut buffer[1..], length_stack)?)
- }
- else { Ok(()) }
- },
- }
- }
-
- fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result {
- match buffer[0] {
- 0 => {
- match buffer.len() {
- 1 => Ok(Ok(R::from_empty_bytes()?)),
- _ => Ok(Ok(R::from_bytes(&buffer[1..], length_stack)?)),
- }
- }
- 1 => Ok(Err(E::from_bytes(&buffer[1..], length_stack)?)),
- _ => Err(BinaryConvertError::variant(buffer[0]))
- }
- }
-
- fn len_params() -> usize {
- 1
- }
-}
-
-impl BinaryConvertable for BTreeMap where K : BinaryConvertable + Ord, V: BinaryConvertable {
- fn size(&self) -> usize {
- 0usize + match K::len_params() {
- 0 => mem::size_of::() * self.len(),
- _ => self.iter().fold(0usize, |acc, (k, _)| acc + k.size())
- } + match V::len_params() {
- 0 => mem::size_of::() * self.len(),
- _ => self.iter().fold(0usize, |acc, (_, v)| acc + v.size())
- }
- }
-
- fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> {
- let mut offset = 0usize;
- for (key, val) in self.iter() {
- let key_size = match K::len_params() {
- 0 => mem::size_of::(),
- _ => { let size = key.size(); length_stack.push_back(size); size }
- };
- let val_size = match K::len_params() {
- 0 => mem::size_of::(),
- _ => { let size = val.size(); length_stack.push_back(size); size }
- };
-
- if key_size > 0 {
- let item_end = offset + key_size;
- key.to_bytes(&mut buffer[offset..item_end], length_stack)?;
- offset = item_end;
- }
-
- if val_size > 0 {
- let item_end = offset + key_size;
- val.to_bytes(&mut buffer[offset..item_end], length_stack)?;
- offset = item_end;
- }
- }
- Ok(())
- }
-
- fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result {
- let mut index = 0;
- let mut result = Self::new();
-
- if buffer.len() == 0 { return Ok(result); }
-
- loop {
- let key_size = match K::len_params() {
- 0 => mem::size_of::(),
- _ => length_stack.pop_front().ok_or(BinaryConvertError::length())?,
- };
- let key = if key_size == 0 {
- K::from_empty_bytes()?
- } else {
- if index + key_size > buffer.len() {
- return Err(BinaryConvertError::boundaries())
- }
- K::from_bytes(&buffer[index..index+key_size], length_stack)?
- };
- index = index + key_size;
-
- let val_size = match V::len_params() {
- 0 => mem::size_of::(),
- _ => length_stack.pop_front().ok_or(BinaryConvertError::length())?,
- };
- let val = if val_size == 0 {
- V::from_empty_bytes()?
- } else {
- if index + val_size > buffer.len() {
- return Err(BinaryConvertError::boundaries())
- }
- V::from_bytes(&buffer[index..index+val_size], length_stack)?
- };
- result.insert(key, val);
- index = index + val_size;
-
- if index == buffer.len() { break; }
- if index > buffer.len() {
- return Err(BinaryConvertError::boundaries())
- }
- }
-
- Ok(result)
- }
-
- fn from_empty_bytes() -> Result {
- Ok(Self::new())
- }
-
- fn len_params() -> usize {
- 1
- }
-}
-
-impl BinaryConvertable for VecDeque where T: BinaryConvertable {
- fn size(&self) -> usize {
- match T::len_params() {
- 0 => mem::size_of::() * self.len(),
- _ => self.iter().fold(0usize, |acc, t| acc + t.size()),
- }
- }
-
- fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> {
- let mut offset = 0usize;
- for item in self.iter() {
- let next_size = match T::len_params() {
- 0 => mem::size_of::(),
- _ => { let size = item.size(); length_stack.push_back(size); size },
- };
- if next_size > 0 {
- let item_end = offset + next_size;
- item.to_bytes(&mut buffer[offset..item_end], length_stack)?;
- offset = item_end;
- }
- }
- Ok(())
- }
-
- fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result {
- let mut index = 0;
- let mut result = Self::with_capacity(
- match T::len_params() {
- 0 => buffer.len() / mem::size_of::(),
- _ => 128,
- });
-
- if buffer.len() == 0 { return Ok(result); }
-
- loop {
- let next_size = match T::len_params() {
- 0 => mem::size_of::(),
- _ => length_stack.pop_front().ok_or(BinaryConvertError::length())?,
- };
- let item = if next_size == 0 {
- T::from_empty_bytes()?
- }
- else {
- if index + next_size > buffer.len() {
- return Err(BinaryConvertError::boundaries())
- }
- T::from_bytes(&buffer[index..index+next_size], length_stack)?
- };
- result.push_back(item);
-
- index = index + next_size;
- if index == buffer.len() { break; }
- if index > buffer.len() {
- return Err(BinaryConvertError::boundaries())
- }
- }
-
- Ok(result)
- }
-
- fn from_empty_bytes() -> Result {
- Ok(Self::new())
- }
-
- fn len_params() -> usize {
- 1
- }
-}
-
-impl BinaryConvertable for Vec where T: BinaryConvertable {
- fn size(&self) -> usize {
- match T::len_params() {
- 0 => mem::size_of::() * self.len(),
- _ => self.iter().fold(0usize, |acc, t| acc + t.size()),
- }
- }
-
- fn to_bytes(&self, buffer: &mut [u8], length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> {
- let mut offset = 0usize;
- for item in self.iter() {
- let next_size = match T::len_params() {
- 0 => mem::size_of::(),
- _ => { let size = item.size(); length_stack.push_back(size); size },
- };
- if next_size > 0 {
- let item_end = offset + next_size;
- item.to_bytes(&mut buffer[offset..item_end], length_stack)?;
- offset = item_end;
- }
- }
- Ok(())
- }
-
- fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque) -> Result {
- let mut index = 0;
- let mut result = Self::with_capacity(
- match T::len_params() {
- 0 => buffer.len() / mem::size_of::(),
- _ => 128,
- });
-
- if buffer.len() == 0 { return Ok(result); }
-
- loop {
- let next_size = match T::len_params() {
- 0 => mem::size_of::(),
- _ => length_stack.pop_front().ok_or(BinaryConvertError::length())?,
- };
- let item = if next_size == 0 {
- T::from_empty_bytes()?
- }
- else {
- if index + next_size > buffer.len() {
- return Err(BinaryConvertError::boundaries())
- }
- T::from_bytes(&buffer[index..index+next_size], length_stack)?
- };
- result.push(item);
-
- index = index + next_size;
- if index == buffer.len() { break; }
- if index > buffer.len() {
- return Err(BinaryConvertError::boundaries())
- }
- }
-
- Ok(result)
- }
-
- fn from_empty_bytes() -> Result {
- Ok(Self::new())
- }
-
- fn len_params() -> usize {
- 1
- }
-}
-
-impl BinaryConvertable for String {
- fn size(&self) -> usize {
- self.as_bytes().len()
- }
-
- fn from_empty_bytes() -> Result {
- Ok(String::new())
- }
-
- fn to_bytes(&self, buffer: &mut [u8], _length_stack: &mut VecDeque) -> Result<(), BinaryConvertError> {
- buffer[..].clone_from_slice(self.as_bytes());
- Ok(())
- }
-
- fn from_bytes(buffer: &[u8], _length_stack: &mut VecDeque