Unverified Commit b8604116 authored by Georgy Shepelev's avatar Georgy Shepelev Committed by GitHub
Browse files

Add ability to re-export parity-scale-codec crate (#325)

* use codec_crate_path for all derivable macros

* update README

* bump versions

* use `codec` attribute in tests

* remove redundant call to parse_quote
parent 6f134662
Pipeline #181954 passed with stages
in 19 minutes and 53 seconds
......@@ -423,7 +423,7 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "parity-scale-codec"
version = "3.0.0"
version = "3.1.0"
dependencies = [
"arbitrary",
"arrayvec",
......@@ -443,7 +443,7 @@ dependencies = [
[[package]]
name = "parity-scale-codec-derive"
version = "3.0.0"
version = "3.1.0"
dependencies = [
"parity-scale-codec",
"proc-macro-crate",
......
[package]
name = "parity-scale-codec"
description = "SCALE - Simple Concatenating Aggregated Little Endians"
version = "3.0.0"
version = "3.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "Apache-2.0"
repository = "https://github.com/paritytech/parity-scale-codec"
......@@ -12,7 +12,7 @@ rust-version = "1.56.1"
[dependencies]
arrayvec = { version = "0.7", default-features = false }
serde = { version = "1.0.102", optional = true }
parity-scale-codec-derive = { path = "derive", version = "3.0.0", default-features = false, optional = true }
parity-scale-codec-derive = { path = "derive", version = "3.1.0", default-features = false, optional = true }
bitvec = { version = "1", default-features = false, features = [ "alloc" ], optional = true }
bytes = { version = "1", default-features = false, optional = true }
byte-slice-cast = { version = "1.0.0", default-features = false }
......
......@@ -201,6 +201,9 @@ The derive implementation supports the following attributes:
- `codec(index = 0)`: Needs to be placed above an enum variant to make the variant use the given
index when encoded. By default the index is determined by counting from `0` beginning wth the
first variant.
- `codec(crate = path::to::crate)`: Specify a path to the parity-scale-codec crate instance to use
when referring to Codec APIs from generated code. This is normally only applicable when invoking
re-exported Codec derives from a public macro in a different crate.
License: Apache-2.0
[package]
name = "parity-scale-codec-derive"
description = "Serialization and deserialization derive macro for Parity SCALE Codec"
version = "3.0.0"
version = "3.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "Apache-2.0"
edition = "2021"
......
......@@ -31,7 +31,7 @@ pub fn quote(
type_name: &Ident,
type_generics: &TokenStream,
input: &TokenStream,
crate_ident: &TokenStream,
crate_path: &syn::Path,
) -> TokenStream {
match *data {
Data::Struct(ref data) => match data.fields {
......@@ -40,7 +40,7 @@ pub fn quote(
&type_name.to_string(),
input,
&data.fields,
crate_ident,
crate_path,
),
Fields::Unit => {
quote_spanned! { data.fields.span() =>
......@@ -67,7 +67,7 @@ pub fn quote(
&format!("{}::{}", type_name, name),
input,
&v.fields,
crate_ident,
crate_path,
);
quote_spanned! { v.span() =>
......@@ -101,7 +101,7 @@ pub fn quote(
}
}
fn create_decode_expr(field: &Field, name: &str, input: &TokenStream, crate_ident: &TokenStream) -> TokenStream {
fn create_decode_expr(field: &Field, name: &str, input: &TokenStream, crate_path: &syn::Path) -> TokenStream {
let encoded_as = utils::get_encoded_as_type(field);
let compact = utils::is_compact(field);
let skip = utils::should_skip(&field.attrs);
......@@ -122,7 +122,7 @@ fn create_decode_expr(field: &Field, name: &str, input: &TokenStream, crate_iden
quote_spanned! { field.span() =>
{
let #res = <
<#field_type as #crate_ident::HasCompact>::Type as #crate_ident::Decode
<#field_type as #crate_path::HasCompact>::Type as #crate_path::Decode
>::decode(#input);
match #res {
::core::result::Result::Err(e) => return ::core::result::Result::Err(e.chain(#err_msg)),
......@@ -133,7 +133,7 @@ fn create_decode_expr(field: &Field, name: &str, input: &TokenStream, crate_iden
} else if let Some(encoded_as) = encoded_as {
quote_spanned! { field.span() =>
{
let #res = <#encoded_as as #crate_ident::Decode>::decode(#input);
let #res = <#encoded_as as #crate_path::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(),
......@@ -146,7 +146,7 @@ fn create_decode_expr(field: &Field, name: &str, input: &TokenStream, crate_iden
let field_type = &field.ty;
quote_spanned! { field.span() =>
{
let #res = <#field_type as #crate_ident::Decode>::decode(#input);
let #res = <#field_type as #crate_path::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,
......@@ -161,7 +161,7 @@ fn create_instance(
name_str: &str,
input: &TokenStream,
fields: &Fields,
crate_ident: &TokenStream,
crate_path: &syn::Path,
) -> TokenStream {
match *fields {
Fields::Named(ref fields) => {
......@@ -171,7 +171,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, crate_ident);
let decode = create_decode_expr(f, &field_name, input, crate_path);
quote_spanned! { f.span() =>
#name_ident: #decode
......@@ -188,7 +188,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, crate_ident)
create_decode_expr(f, &field_name, input, crate_path)
});
quote_spanned! { fields.span() =>
......
......@@ -30,7 +30,7 @@ type FieldsList = Punctuated<Field, Comma>;
fn encode_single_field(
field: &Field,
field_name: TokenStream,
crate_ident: &TokenStream,
crate_path: &syn::Path,
) -> TokenStream {
let encoded_as = utils::get_encoded_as_type(field);
let compact = utils::is_compact(field);
......@@ -53,8 +53,8 @@ fn encode_single_field(
let field_type = &field.ty;
quote_spanned! {
field.span() => {
<<#field_type as #crate_ident::HasCompact>::Type as
#crate_ident::EncodeAsRef<'_, #field_type>>::RefType::from(#field_name)
<<#field_type as #crate_path::HasCompact>::Type as
#crate_path::EncodeAsRef<'_, #field_type>>::RefType::from(#field_name)
}
}
} else if let Some(encoded_as) = encoded_as {
......@@ -62,7 +62,7 @@ fn encode_single_field(
quote_spanned! {
field.span() => {
<#encoded_as as
#crate_ident::EncodeAsRef<'_, #field_type>>::RefType::from(#field_name)
#crate_path::EncodeAsRef<'_, #field_type>>::RefType::from(#field_name)
}
}
} else {
......@@ -75,19 +75,19 @@ fn encode_single_field(
let i_self = quote! { self };
quote_spanned! { field.span() =>
fn encode_to<__CodecOutputEdqy: #crate_ident::Output + ?::core::marker::Sized>(
fn encode_to<__CodecOutputEdqy: #crate_path::Output + ?::core::marker::Sized>(
&#i_self,
__codec_dest_edqy: &mut __CodecOutputEdqy
) {
#crate_ident::Encode::encode_to(&#final_field_variable, __codec_dest_edqy)
#crate_path::Encode::encode_to(&#final_field_variable, __codec_dest_edqy)
}
fn encode(&#i_self) -> #crate_ident::alloc::vec::Vec<::core::primitive::u8> {
#crate_ident::Encode::encode(&#final_field_variable)
fn encode(&#i_self) -> #crate_path::alloc::vec::Vec<::core::primitive::u8> {
#crate_path::Encode::encode(&#final_field_variable)
}
fn using_encoded<R, F: ::core::ops::FnOnce(&[::core::primitive::u8]) -> R>(&#i_self, f: F) -> R {
#crate_ident::Encode::using_encoded(&#final_field_variable, f)
#crate_path::Encode::using_encoded(&#final_field_variable, f)
}
}
}
......@@ -96,7 +96,7 @@ fn encode_fields<F>(
dest: &TokenStream,
fields: &FieldsList,
field_name: F,
crate_ident: &TokenStream,
crate_path: &syn::Path,
) -> TokenStream where
F: Fn(usize, &Option<Ident>) -> TokenStream,
{
......@@ -119,10 +119,10 @@ fn encode_fields<F>(
let field_type = &f.ty;
quote_spanned! {
f.span() => {
#crate_ident::Encode::encode_to(
#crate_path::Encode::encode_to(
&<
<#field_type as #crate_ident::HasCompact>::Type as
#crate_ident::EncodeAsRef<'_, #field_type>
<#field_type as #crate_path::HasCompact>::Type as
#crate_path::EncodeAsRef<'_, #field_type>
>::RefType::from(#field),
#dest,
);
......@@ -132,10 +132,10 @@ fn encode_fields<F>(
let field_type = &f.ty;
quote_spanned! {
f.span() => {
#crate_ident::Encode::encode_to(
#crate_path::Encode::encode_to(
&<
#encoded_as as
#crate_ident::EncodeAsRef<'_, #field_type>
#crate_path::EncodeAsRef<'_, #field_type>
>::RefType::from(#field),
#dest,
);
......@@ -147,7 +147,7 @@ fn encode_fields<F>(
}
} else {
quote_spanned! { f.span() =>
#crate_ident::Encode::encode_to(#field, #dest);
#crate_path::Encode::encode_to(#field, #dest);
}
}
});
......@@ -157,7 +157,7 @@ fn encode_fields<F>(
}
}
fn try_impl_encode_single_field_optimisation(data: &Data, crate_ident: &TokenStream) -> Option<TokenStream> {
fn try_impl_encode_single_field_optimisation(data: &Data, crate_path: &syn::Path) -> Option<TokenStream> {
match *data {
Data::Struct(ref data) => {
match data.fields {
......@@ -167,7 +167,7 @@ fn try_impl_encode_single_field_optimisation(data: &Data, crate_ident: &TokenStr
Some(encode_single_field(
field,
quote!(&self.#name),
crate_ident,
crate_path,
))
},
Fields::Unnamed(ref fields) if utils::filter_skip_unnamed(fields).count() == 1 => {
......@@ -177,7 +177,7 @@ fn try_impl_encode_single_field_optimisation(data: &Data, crate_ident: &TokenStr
Some(encode_single_field(
field,
quote!(&self.#id),
crate_ident,
crate_path,
))
},
_ => None,
......@@ -187,7 +187,7 @@ fn try_impl_encode_single_field_optimisation(data: &Data, crate_ident: &TokenStr
}
}
fn impl_encode(data: &Data, type_name: &Ident, crate_ident: &TokenStream) -> TokenStream {
fn impl_encode(data: &Data, type_name: &Ident, crate_path: &syn::Path) -> TokenStream {
let self_ = quote!(self);
let dest = &quote!(__codec_dest_edqy);
let encoding = match *data {
......@@ -197,7 +197,7 @@ fn impl_encode(data: &Data, type_name: &Ident, crate_ident: &TokenStream) -> Tok
dest,
&fields.named,
|_, name| quote!(&#self_.#name),
crate_ident,
crate_path,
),
Fields::Unnamed(ref fields) => encode_fields(
dest,
......@@ -206,7 +206,7 @@ fn impl_encode(data: &Data, type_name: &Ident, crate_ident: &TokenStream) -> Tok
let i = syn::Index::from(i);
quote!(&#self_.#i)
},
crate_ident,
crate_path,
),
Fields::Unit => quote!(),
}
......@@ -242,7 +242,7 @@ fn impl_encode(data: &Data, type_name: &Ident, crate_ident: &TokenStream) -> Tok
dest,
&fields.named,
|a, b| field_name(a, b),
crate_ident,
crate_path,
);
quote_spanned! { f.span() =>
......@@ -268,7 +268,7 @@ fn impl_encode(data: &Data, type_name: &Ident, crate_ident: &TokenStream) -> Tok
dest,
&fields.unnamed,
|a, b| field_name(a, b),
crate_ident,
crate_path,
);
quote_spanned! { f.span() =>
......@@ -301,7 +301,7 @@ fn impl_encode(data: &Data, type_name: &Ident, crate_ident: &TokenStream) -> Tok
).to_compile_error(),
};
quote! {
fn encode_to<__CodecOutputEdqy: #crate_ident::Output + ?::core::marker::Sized>(
fn encode_to<__CodecOutputEdqy: #crate_path::Output + ?::core::marker::Sized>(
&#self_,
#dest: &mut __CodecOutputEdqy
) {
......@@ -310,11 +310,11 @@ fn impl_encode(data: &Data, type_name: &Ident, crate_ident: &TokenStream) -> Tok
}
}
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) {
pub fn quote(data: &Data, type_name: &Ident, crate_path: &syn::Path) -> TokenStream {
if let Some(implementation) = try_impl_encode_single_field_optimisation(data, crate_path) {
implementation
} else {
impl_encode(data, type_name, crate_ident)
impl_encode(data, type_name, crate_path)
}
}
......
......@@ -23,12 +23,9 @@ extern crate syn;
#[macro_use]
extern crate quote;
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;
use crate::utils::{codec_crate_path, is_lint_attribute};
mod decode;
mod encode;
......@@ -36,30 +33,6 @@ mod max_encoded_len;
mod utils;
mod trait_bounds;
/// 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<TokenStream2, Error> {
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() == CRATE_NAME {
Ok(root_import("parity_scale_codec"))
} else {
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 attrs = input.attrs.into_iter().filter(is_lint_attribute);
......@@ -156,8 +129,8 @@ 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,
let crate_path = match codec_crate_path(&input.attrs) {
Ok(crate_path) => crate_path,
Err(error) => {
return error.into_compile_error().into()
}
......@@ -169,10 +142,10 @@ pub fn encode_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream
&input.ident,
&mut input.generics,
&input.data,
parse_quote!(#crate_ident::Encode),
parse_quote!(#crate_path::Encode),
None,
utils::has_dumb_trait_bound(&input.attrs),
&crate_ident,
&crate_path,
) {
return e.to_compile_error().into();
}
......@@ -180,14 +153,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, &crate_ident);
let encode_impl = encode::quote(&input.data, name, &crate_path);
let impl_block = quote! {
impl #impl_generics #crate_ident::Encode for #name #ty_generics #where_clause {
impl #impl_generics #crate_path::Encode for #name #ty_generics #where_clause {
#encode_impl
}
impl #impl_generics #crate_ident::EncodeLike for #name #ty_generics #where_clause {}
impl #impl_generics #crate_path::EncodeLike for #name #ty_generics #where_clause {}
};
wrap_with_dummy_const(input, impl_block)
......@@ -207,8 +180,8 @@ 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,
let crate_path = match codec_crate_path(&input.attrs) {
Ok(crate_path) => crate_path,
Err(error) => {
return error.into_compile_error().into()
}
......@@ -220,10 +193,10 @@ pub fn decode_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream
&input.ident,
&mut input.generics,
&input.data,
parse_quote!(#crate_ident::Decode),
parse_quote!(#crate_path::Decode),
Some(parse_quote!(Default)),
utils::has_dumb_trait_bound(&input.attrs),
&crate_ident,
&crate_path,
) {
return e.to_compile_error().into();
}
......@@ -233,13 +206,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, &quote!(#ty_gen_turbofish), &input_, &crate_ident);
let decoding = decode::quote(&input.data, name, &quote!(#ty_gen_turbofish), &input_, &crate_path);
let impl_block = quote! {
impl #impl_generics #crate_ident::Decode for #name #ty_generics #where_clause {
fn decode<__CodecInputEdqy: #crate_ident::Input>(
impl #impl_generics #crate_path::Decode for #name #ty_generics #where_clause {
fn decode<__CodecInputEdqy: #crate_path::Input>(
#input_: &mut __CodecInputEdqy
) -> ::core::result::Result<Self, #crate_ident::Error> {
) -> ::core::result::Result<Self, #crate_path::Error> {
#decoding
}
}
......@@ -273,8 +246,8 @@ 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,
let crate_path = match codec_crate_path(&input.attrs) {
Ok(crate_path) => crate_path,
Err(error) => {
return error.into_compile_error().into()
}
......@@ -284,10 +257,10 @@ pub fn compact_as_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStr
&input.ident,
&mut input.generics,
&input.data,
parse_quote!(#crate_ident::CompactAs),
parse_quote!(#crate_path::CompactAs),
None,
utils::has_dumb_trait_bound(&input.attrs),
&crate_ident,
&crate_path,
) {
return e.to_compile_error().into();
}
......@@ -343,22 +316,22 @@ pub fn compact_as_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStr
};
let impl_block = quote! {
impl #impl_generics #crate_ident::CompactAs for #name #ty_generics #where_clause {
impl #impl_generics #crate_path::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, #crate_ident::Error>
-> ::core::result::Result<#name #ty_generics, #crate_path::Error>
{
::core::result::Result::Ok(#constructor)
}
}
impl #impl_generics From<#crate_ident::Compact<#name #ty_generics>>
impl #impl_generics From<#crate_path::Compact<#name #ty_generics>>
for #name #ty_generics #where_clause
{
fn from(x: #crate_ident::Compact<#name #ty_generics>) -> #name #ty_generics {
fn from(x: #crate_path::Compact<#name #ty_generics>) -> #name #ty_generics {
x.0
}
}
......
......@@ -14,7 +14,7 @@
use std::iter;
use proc_macro2::{Ident, TokenStream};
use proc_macro2::Ident;
use syn::{
spanned::Spanned,
visit::{self, Visit},
......@@ -112,7 +112,7 @@ pub fn add(
codec_bound: syn::Path,
codec_skip_bound: Option<syn::Path>,
dumb_trait_bounds: bool,
crate_ident: &TokenStream,
crate_path: &syn::Path,
) -> Result<()> {
let ty_params = generics.type_params().map(|p| p.ident.clone()).collect::<Vec<_>>();
if ty_params.is_empty() {
......@@ -147,7 +147,7 @@ pub fn add(
where_clause.predicates.push(parse_quote!(#ty : #codec_bound))
});
let has_compact_bound: syn::Path = parse_quote!(#crate_ident::HasCompact);
let has_compact_bound: syn::Path = parse_quote!(#crate_path::HasCompact);
compact_types
.into_iter()
.for_each(|ty| {
......
......@@ -121,7 +121,6 @@ pub fn has_dumb_trait_bound(attrs: &[Attribute]) -> bool {
}
/// Generate the crate access for the crate using 2018 syntax.
#[cfg(feature = "max-encoded-len")]
fn crate_access() -> syn::Result<proc_macro2::Ident> {
use proc_macro_crate::{crate_name, FoundCrate};
use proc_macro2::{Span, Ident};
......@@ -173,7 +172,6 @@ fn codec_crate_path_inner(attr: &Attribute) -> Option<Path> {
/// If not found, returns the default crate access pattern.
///
/// If multiple items match the pattern, all but the first are ignored.
#[cfg(feature = "max-encoded-len")]
pub fn codec_crate_path(attrs: &[Attribute]) -> syn::Result<Path> {
match attrs.iter().find_map(codec_crate_path_inner) {
Some(path) => Ok(path),
......
#![no_implicit_prelude]
#[derive(::parity_scale_codec::Decode)]
#[codec(crate = ::parity_scale_codec)]
pub struct Struct {
field_1: i8,
field_2: i16,
......@@ -9,6 +10,7 @@ pub struct Struct {
}
#[derive(::parity_scale_codec::Decode)]
#[codec(crate = ::parity_scale_codec)]
pub enum Enum {
Variant1,
Variant2(i8, i16, i32, i64),
......
#![no_implicit_prelude]
#[derive(::parity_scale_codec::Encode)]
#[codec(crate = ::parity_scale_codec)]
pub struct Struct {
field_1: i8,
field_2: i16,
......@@ -9,6 +10,7 @@ pub struct Struct {
}
#[derive(::parity_scale_codec::Encode)]
#[codec(crate = ::parity_scale_codec)]
pub enum Enum {
Variant1,
Variant2(i8, i16, i32, i64),
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment