From 4fa5ddf786742b924eec7ef0b794815ea02c9ae6 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Mon, 13 Sep 2021 16:54:41 +0200 Subject: [PATCH] Minor codegen hygiene improvements and modernizations (#291) --- derive/src/decode.rs | 18 ++++--- derive/src/encode.rs | 53 ++++++++++++--------- derive/src/lib.rs | 89 ++++++++++++++++++++++------------- derive/src/max_encoded_len.rs | 2 +- derive/src/trait_bounds.rs | 5 +- 5 files changed, 102 insertions(+), 65 deletions(-) diff --git a/derive/src/decode.rs b/derive/src/decode.rs index bb1ce34b..10583256 100644 --- a/derive/src/decode.rs +++ b/derive/src/decode.rs @@ -31,6 +31,7 @@ pub fn quote( type_name: &Ident, type_generics: &TokenStream, input: &TokenStream, + crate_ident: &TokenStream, ) -> TokenStream { match *data { Data::Struct(ref data) => match data.fields { @@ -39,6 +40,7 @@ pub fn quote( &type_name.to_string(), input, &data.fields, + crate_ident, ), Fields::Unit => { quote_spanned! { data.fields.span() => @@ -65,6 +67,7 @@ pub fn quote( &format!("{}::{}", type_name, name), input, &v.fields, + crate_ident, ); quote_spanned! { v.span() => @@ -96,7 +99,7 @@ pub fn quote( } } -fn create_decode_expr(field: &Field, name: &str, input: &TokenStream) -> TokenStream { +fn create_decode_expr(field: &Field, name: &str, input: &TokenStream, crate_ident: &TokenStream) -> TokenStream { let encoded_as = utils::get_encoded_as_type(field); let compact = utils::is_compact(field); let skip = utils::should_skip(&field.attrs); @@ -117,7 +120,7 @@ fn create_decode_expr(field: &Field, name: &str, input: &TokenStream) -> TokenSt quote_spanned! { field.span() => { let #res = < - <#field_type as _parity_scale_codec::HasCompact>::Type as _parity_scale_codec::Decode + <#field_type as #crate_ident::HasCompact>::Type as #crate_ident::Decode >::decode(#input); match #res { ::core::result::Result::Err(e) => return ::core::result::Result::Err(e.chain(#err_msg)), @@ -128,7 +131,7 @@ fn create_decode_expr(field: &Field, name: &str, input: &TokenStream) -> TokenSt } else if let Some(encoded_as) = encoded_as { quote_spanned! { field.span() => { - let #res = <#encoded_as as _parity_scale_codec::Decode>::decode(#input); + let #res = <#encoded_as as #crate_ident::Decode>::decode(#input); match #res { ::core::result::Result::Err(e) => return ::core::result::Result::Err(e.chain(#err_msg)), ::core::result::Result::Ok(#res) => #res.into(), @@ -141,7 +144,7 @@ fn create_decode_expr(field: &Field, name: &str, input: &TokenStream) -> TokenSt let field_type = &field.ty; quote_spanned! { field.span() => { - let #res = <#field_type as _parity_scale_codec::Decode>::decode(#input); + let #res = <#field_type as #crate_ident::Decode>::decode(#input); match #res { ::core::result::Result::Err(e) => return ::core::result::Result::Err(e.chain(#err_msg)), ::core::result::Result::Ok(#res) => #res, @@ -155,7 +158,8 @@ fn create_instance( name: TokenStream, name_str: &str, input: &TokenStream, - fields: &Fields + fields: &Fields, + crate_ident: &TokenStream, ) -> TokenStream { match *fields { Fields::Named(ref fields) => { @@ -165,7 +169,7 @@ fn create_instance( Some(a) => format!("{}::{}", name_str, a), None => format!("{}", name_str), // Should never happen, fields are named. }; - let decode = create_decode_expr(f, &field_name, input); + let decode = create_decode_expr(f, &field_name, input, crate_ident); quote_spanned! { f.span() => #name_ident: #decode @@ -182,7 +186,7 @@ fn create_instance( let recurse = fields.unnamed.iter().enumerate().map(|(i, f) | { let field_name = format!("{}.{}", name_str, i); - create_decode_expr(f, &field_name, input) + create_decode_expr(f, &field_name, input, crate_ident) }); quote_spanned! { fields.span() => diff --git a/derive/src/encode.rs b/derive/src/encode.rs index 434d4f3c..3e385182 100644 --- a/derive/src/encode.rs +++ b/derive/src/encode.rs @@ -30,6 +30,7 @@ type FieldsList = Punctuated; fn encode_single_field( field: &Field, field_name: TokenStream, + crate_ident: &TokenStream, ) -> TokenStream { let encoded_as = utils::get_encoded_as_type(field); let compact = utils::is_compact(field); @@ -52,8 +53,8 @@ fn encode_single_field( let field_type = &field.ty; quote_spanned! { field.span() => { - <<#field_type as _parity_scale_codec::HasCompact>::Type as - _parity_scale_codec::EncodeAsRef<'_, #field_type>>::RefType::from(#field_name) + <<#field_type as #crate_ident::HasCompact>::Type as + #crate_ident::EncodeAsRef<'_, #field_type>>::RefType::from(#field_name) } } } else if let Some(encoded_as) = encoded_as { @@ -61,7 +62,7 @@ fn encode_single_field( quote_spanned! { field.span() => { <#encoded_as as - _parity_scale_codec::EncodeAsRef<'_, #field_type>>::RefType::from(#field_name) + #crate_ident::EncodeAsRef<'_, #field_type>>::RefType::from(#field_name) } } } else { @@ -74,19 +75,19 @@ fn encode_single_field( let i_self = quote! { self }; quote_spanned! { field.span() => - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output + ?Sized>( + fn encode_to<__CodecOutputEdqy: #crate_ident::Output + ?::core::marker::Sized>( &#i_self, __codec_dest_edqy: &mut __CodecOutputEdqy ) { - _parity_scale_codec::Encode::encode_to(&#final_field_variable, __codec_dest_edqy) + #crate_ident::Encode::encode_to(&#final_field_variable, __codec_dest_edqy) } - fn encode(&#i_self) -> _parity_scale_codec::alloc::vec::Vec { - _parity_scale_codec::Encode::encode(&#final_field_variable) + fn encode(&#i_self) -> #crate_ident::alloc::vec::Vec<::core::primitive::u8> { + #crate_ident::Encode::encode(&#final_field_variable) } fn using_encoded R>(&#i_self, f: F) -> R { - _parity_scale_codec::Encode::using_encoded(&#final_field_variable, f) + #crate_ident::Encode::using_encoded(&#final_field_variable, f) } } } @@ -95,6 +96,7 @@ fn encode_fields( dest: &TokenStream, fields: &FieldsList, field_name: F, + crate_ident: &TokenStream, ) -> TokenStream where F: Fn(usize, &Option) -> TokenStream, { @@ -117,10 +119,10 @@ fn encode_fields( let field_type = &f.ty; quote_spanned! { f.span() => { - _parity_scale_codec::Encode::encode_to( + #crate_ident::Encode::encode_to( &< - <#field_type as _parity_scale_codec::HasCompact>::Type as - _parity_scale_codec::EncodeAsRef<'_, #field_type> + <#field_type as #crate_ident::HasCompact>::Type as + #crate_ident::EncodeAsRef<'_, #field_type> >::RefType::from(#field), #dest, ); @@ -130,10 +132,10 @@ fn encode_fields( let field_type = &f.ty; quote_spanned! { f.span() => { - _parity_scale_codec::Encode::encode_to( + #crate_ident::Encode::encode_to( &< #encoded_as as - _parity_scale_codec::EncodeAsRef<'_, #field_type> + #crate_ident::EncodeAsRef<'_, #field_type> >::RefType::from(#field), #dest, ); @@ -145,7 +147,7 @@ fn encode_fields( } } else { quote_spanned! { f.span() => - _parity_scale_codec::Encode::encode_to(#field, #dest); + #crate_ident::Encode::encode_to(#field, #dest); } } }); @@ -155,7 +157,7 @@ fn encode_fields( } } -fn try_impl_encode_single_field_optimisation(data: &Data) -> Option { +fn try_impl_encode_single_field_optimisation(data: &Data, crate_ident: &TokenStream) -> Option { match *data { Data::Struct(ref data) => { match data.fields { @@ -164,7 +166,8 @@ fn try_impl_encode_single_field_optimisation(data: &Data) -> Option let name = &field.ident; Some(encode_single_field( field, - quote!(&self.#name) + quote!(&self.#name), + crate_ident, )) }, Fields::Unnamed(ref fields) if utils::filter_skip_unnamed(fields).count() == 1 => { @@ -173,7 +176,8 @@ fn try_impl_encode_single_field_optimisation(data: &Data) -> Option Some(encode_single_field( field, - quote!(&self.#id) + quote!(&self.#id), + crate_ident, )) }, _ => None, @@ -183,7 +187,7 @@ fn try_impl_encode_single_field_optimisation(data: &Data) -> Option } } -fn impl_encode(data: &Data, type_name: &Ident) -> TokenStream { +fn impl_encode(data: &Data, type_name: &Ident, crate_ident: &TokenStream) -> TokenStream { let self_ = quote!(self); let dest = "e!(__codec_dest_edqy); let encoding = match *data { @@ -193,6 +197,7 @@ fn impl_encode(data: &Data, type_name: &Ident) -> TokenStream { dest, &fields.named, |_, name| quote!(&#self_.#name), + crate_ident, ), Fields::Unnamed(ref fields) => encode_fields( dest, @@ -201,6 +206,7 @@ fn impl_encode(data: &Data, type_name: &Ident) -> TokenStream { let i = syn::Index::from(i); quote!(&#self_.#i) }, + crate_ident, ), Fields::Unit => quote!(), } @@ -236,6 +242,7 @@ fn impl_encode(data: &Data, type_name: &Ident) -> TokenStream { dest, &fields.named, |a, b| field_name(a, b), + crate_ident, ); quote_spanned! { f.span() => @@ -261,6 +268,7 @@ fn impl_encode(data: &Data, type_name: &Ident) -> TokenStream { dest, &fields.unnamed, |a, b| field_name(a, b), + crate_ident, ); quote_spanned! { f.span() => @@ -292,9 +300,8 @@ fn impl_encode(data: &Data, type_name: &Ident) -> TokenStream { "Union types are not supported." ).to_compile_error(), }; - quote! { - fn encode_to<__CodecOutputEdqy: _parity_scale_codec::Output + ?Sized>( + fn encode_to<__CodecOutputEdqy: #crate_ident::Output + ?::core::marker::Sized>( &#self_, #dest: &mut __CodecOutputEdqy ) { @@ -303,11 +310,11 @@ fn impl_encode(data: &Data, type_name: &Ident) -> TokenStream { } } -pub fn quote(data: &Data, type_name: &Ident) -> TokenStream { - if let Some(implementation) = try_impl_encode_single_field_optimisation(data) { +pub fn quote(data: &Data, type_name: &Ident, crate_ident: &TokenStream) -> TokenStream { + if let Some(implementation) = try_impl_encode_single_field_optimisation(data, crate_ident) { implementation } else { - impl_encode(data, type_name) + impl_encode(data, type_name, crate_ident) } } diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 624a912a..baed14dd 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -27,7 +27,7 @@ use proc_macro2::{Ident, Span}; use proc_macro_crate::{crate_name, FoundCrate}; use syn::spanned::Spanned; use syn::{Data, Field, Fields, DeriveInput, Error}; - +use proc_macro2::TokenStream as TokenStream2; use crate::utils::is_lint_attribute; mod decode; @@ -36,34 +36,35 @@ mod max_encoded_len; mod utils; mod trait_bounds; -/// Include the `parity-scale-codec` crate under a known name (`_parity_scale_codec`). -fn include_parity_scale_codec_crate() -> proc_macro2::TokenStream { +/// Returns the identifier of the `parity-scale-codec` crate as used. +/// +/// The identifier might change if the depending crate imported it +/// using a custom package name. +fn parity_scale_codec_ident() -> Result { + static CRATE_NAME: &str = "parity-scale-codec"; + fn root_import(name: &str) -> TokenStream2 { + let ident = Ident::new(name, Span::call_site()); + quote!{ :: #ident } + } // This "hack" is required for the tests. - if std::env::var("CARGO_PKG_NAME").unwrap() == "parity-scale-codec" { - quote!( extern crate parity_scale_codec as _parity_scale_codec; ) + if std::env::var("CARGO_PKG_NAME").unwrap() == CRATE_NAME { + Ok(root_import("parity_scale_codec")) } else { - match crate_name("parity-scale-codec") { - Ok(FoundCrate::Itself) => quote!( extern crate parity_scale_codec as _parity_scale_codec; ), - Ok(FoundCrate::Name(parity_codec_crate)) => { - let ident = Ident::new(&parity_codec_crate, Span::call_site()); - quote!( extern crate #ident as _parity_scale_codec; ) - }, - Err(e) => Error::new(Span::call_site(), &e).to_compile_error(), + match crate_name(CRATE_NAME) { + Ok(FoundCrate::Itself) => { + Ok(quote! { crate }) + } + Ok(FoundCrate::Name(custom_name)) => Ok(root_import(&custom_name)), + Err(e) => Err(Error::new(Span::call_site(), &e)), } } } /// Wraps the impl block in a "dummy const" fn wrap_with_dummy_const(input: DeriveInput, impl_block: proc_macro2::TokenStream) -> proc_macro::TokenStream { - let parity_codec_crate = include_parity_scale_codec_crate(); let attrs = input.attrs.into_iter().filter(is_lint_attribute); - let generated = quote! { const _: () = { - #[allow(unknown_lints)] - #[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))] - #[allow(rust_2018_idioms)] - #parity_codec_crate #(#attrs)* #impl_block }; @@ -148,15 +149,23 @@ pub fn encode_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream return e.to_compile_error().into(); } + let crate_ident = match crate::parity_scale_codec_ident() { + Ok(crate_ident) => crate_ident, + Err(error) => { + return error.into_compile_error().into() + } + }; + if let Some(custom_bound) = utils::custom_encode_trait_bound(&input.attrs) { input.generics.make_where_clause().predicates.extend(custom_bound); } else if let Err(e) = trait_bounds::add( &input.ident, &mut input.generics, &input.data, - parse_quote!(_parity_scale_codec::Encode), + parse_quote!(#crate_ident::Encode), None, utils::has_dumb_trait_bound(&input.attrs), + &crate_ident, ) { return e.to_compile_error().into(); } @@ -164,14 +173,14 @@ pub fn encode_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream let name = &input.ident; let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - let encode_impl = encode::quote(&input.data, name); + let encode_impl = encode::quote(&input.data, name, &crate_ident); let impl_block = quote! { - impl #impl_generics _parity_scale_codec::Encode for #name #ty_generics #where_clause { + impl #impl_generics #crate_ident::Encode for #name #ty_generics #where_clause { #encode_impl } - impl #impl_generics _parity_scale_codec::EncodeLike for #name #ty_generics #where_clause {} + impl #impl_generics #crate_ident::EncodeLike for #name #ty_generics #where_clause {} }; wrap_with_dummy_const(input, impl_block) @@ -191,15 +200,23 @@ pub fn decode_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream return e.to_compile_error().into(); } + let crate_ident = match crate::parity_scale_codec_ident() { + Ok(crate_ident) => crate_ident, + Err(error) => { + return error.into_compile_error().into() + } + }; + if let Some(custom_bound) = utils::custom_decode_trait_bound(&input.attrs) { input.generics.make_where_clause().predicates.extend(custom_bound); } else if let Err(e) = trait_bounds::add( &input.ident, &mut input.generics, &input.data, - parse_quote!(_parity_scale_codec::Decode), + parse_quote!(#crate_ident::Decode), Some(parse_quote!(Default)), utils::has_dumb_trait_bound(&input.attrs), + &crate_ident, ) { return e.to_compile_error().into(); } @@ -209,13 +226,13 @@ pub fn decode_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream let ty_gen_turbofish = ty_generics.as_turbofish(); let input_ = quote!(__codec_input_edqy); - let decoding = decode::quote(&input.data, name, "e!(#ty_gen_turbofish), &input_); + let decoding = decode::quote(&input.data, name, "e!(#ty_gen_turbofish), &input_, &crate_ident); let impl_block = quote! { - impl #impl_generics _parity_scale_codec::Decode for #name #ty_generics #where_clause { - fn decode<__CodecInputEdqy: _parity_scale_codec::Input>( + impl #impl_generics #crate_ident::Decode for #name #ty_generics #where_clause { + fn decode<__CodecInputEdqy: #crate_ident::Input>( #input_: &mut __CodecInputEdqy - ) -> ::core::result::Result { + ) -> ::core::result::Result { #decoding } } @@ -249,13 +266,21 @@ pub fn compact_as_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStr return e.to_compile_error().into(); } + let crate_ident = match crate::parity_scale_codec_ident() { + Ok(crate_ident) => crate_ident, + Err(error) => { + return error.into_compile_error().into() + } + }; + if let Err(e) = trait_bounds::add( &input.ident, &mut input.generics, &input.data, - parse_quote!(_parity_scale_codec::CompactAs), + parse_quote!(#crate_ident::CompactAs), None, utils::has_dumb_trait_bound(&input.attrs), + &crate_ident, ) { return e.to_compile_error().into(); } @@ -311,22 +336,22 @@ pub fn compact_as_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStr }; let impl_block = quote! { - impl #impl_generics _parity_scale_codec::CompactAs for #name #ty_generics #where_clause { + impl #impl_generics #crate_ident::CompactAs for #name #ty_generics #where_clause { type As = #inner_ty; fn encode_as(&self) -> &#inner_ty { #inner_field } fn decode_from(x: #inner_ty) - -> ::core::result::Result<#name #ty_generics, _parity_scale_codec::Error> + -> ::core::result::Result<#name #ty_generics, #crate_ident::Error> { ::core::result::Result::Ok(#constructor) } } - impl #impl_generics From<_parity_scale_codec::Compact<#name #ty_generics>> + impl #impl_generics From<#crate_ident::Compact<#name #ty_generics>> for #name #ty_generics #where_clause { - fn from(x: _parity_scale_codec::Compact<#name #ty_generics>) -> #name #ty_generics { + fn from(x: #crate_ident::Compact<#name #ty_generics>) -> #name #ty_generics { x.0 } } diff --git a/derive/src/max_encoded_len.rs b/derive/src/max_encoded_len.rs index 7a89fe23..35b9fedf 100644 --- a/derive/src/max_encoded_len.rs +++ b/derive/src/max_encoded_len.rs @@ -47,7 +47,7 @@ pub fn derive_max_encoded_len(input: proc_macro::TokenStream) -> proc_macro::Tok quote::quote!( const _: () = { impl #impl_generics #mel_trait for #name #ty_generics #where_clause { - fn max_encoded_len() -> usize { + fn max_encoded_len() -> ::core::primitive::usize { #data_expr } } diff --git a/derive/src/trait_bounds.rs b/derive/src/trait_bounds.rs index c6303f4f..a2361df7 100644 --- a/derive/src/trait_bounds.rs +++ b/derive/src/trait_bounds.rs @@ -14,7 +14,7 @@ use std::iter; -use proc_macro2::Ident; +use proc_macro2::{Ident, TokenStream}; use syn::{ spanned::Spanned, visit::{self, Visit}, @@ -112,6 +112,7 @@ pub fn add( codec_bound: syn::Path, codec_skip_bound: Option, dumb_trait_bounds: bool, + crate_ident: &TokenStream, ) -> Result<()> { let ty_params = generics.type_params().map(|p| p.ident.clone()).collect::>(); if ty_params.is_empty() { @@ -146,7 +147,7 @@ pub fn add( where_clause.predicates.push(parse_quote!(#ty : #codec_bound)) }); - let has_compact_bound: syn::Path = parse_quote!(_parity_scale_codec::HasCompact); + let has_compact_bound: syn::Path = parse_quote!(#crate_ident::HasCompact); compact_types .into_iter() .for_each(|ty| {