Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Use proc macros to generate conversion functions for MultiLocation (#…
Browse files Browse the repository at this point in the history
…3635)

* Use proc macros to generate conversion functions for MultiLocation

* Add compile test and missing conversion cases

* Add common derives for Parent and Ancestor

* Generate conversion functions for MultiLocation v0 via proc macro

* Add type conversion test and fix a bug

* cargo fmt

* Do not hardcode 8 as the number of max parents

* Use map instead of for loops when generating code fragments

* Spelling

* cargo fmt

* More mapping, less for-looping
  • Loading branch information
KiChjang authored and chevdor committed Sep 10, 2021
1 parent eae3adc commit 4e0ab84
Show file tree
Hide file tree
Showing 11 changed files with 486 additions and 647 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ members = [
"xcm/xcm-simulator",
"xcm/xcm-simulator/example",
"xcm/pallet-xcm",
"xcm/procedural",
"node/client",
"node/collation-generation",
"node/core/approval-voting",
Expand Down
1 change: 1 addition & 0 deletions xcm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ impl-trait-for-tuples = "0.2.0"
parity-scale-codec = { version = "2.0.0", default-features = false, features = [ "derive" ] }
derivative = {version = "2.2.0", default-features = false, features = [ "use_core" ] }
log = { version = "0.4.14", default-features = false }
xcm-procedural = { path = "procedural" }

[features]
default = ["std"]
Expand Down
13 changes: 13 additions & 0 deletions xcm/procedural/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
authors = ["Parity Technologies <admin@parity.io>"]
name = "xcm-procedural"
version = "0.1.0"
edition = "2018"

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0.28"
quote = "1.0.9"
syn = "1.0.74"
36 changes: 36 additions & 0 deletions xcm/procedural/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot 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.

// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! Procedural macros used in XCM.
use proc_macro::TokenStream;

mod v0;
mod v1;

#[proc_macro]
pub fn impl_conversion_functions_for_multilocation_v0(input: TokenStream) -> TokenStream {
v0::multilocation::generate_conversion_functions(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}

#[proc_macro]
pub fn impl_conversion_functions_for_multilocation_v1(input: TokenStream) -> TokenStream {
v1::multilocation::generate_conversion_functions(input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}
17 changes: 17 additions & 0 deletions xcm/procedural/src/v0.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot 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.

// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.

pub mod multilocation;
115 changes: 115 additions & 0 deletions xcm/procedural/src/v0/multilocation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot 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.

// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.

use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};

pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> syn::Result<TokenStream> {
if !input.is_empty() {
return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
}

let from_tuples = generate_conversion_from_tuples();
let from_v1 = generate_conversion_from_v1();

Ok(quote! {
#from_tuples
#from_v1
})
}

fn generate_conversion_from_tuples() -> TokenStream {
let from_tuples = (0..8usize)
.map(|num_junctions| {
let junctions =
(0..=num_junctions).map(|_| format_ident!("Junction")).collect::<Vec<_>>();
let idents = (0..=num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
let variant = &format_ident!("X{}", num_junctions + 1);
let array_size = num_junctions + 1;

quote! {
impl From<( #(#junctions,)* )> for MultiLocation {
fn from( ( #(#idents,)* ): ( #(#junctions,)* ) ) -> Self {
MultiLocation::#variant( #(#idents),* )
}
}

impl From<[Junction; #array_size]> for MultiLocation {
fn from(j: [Junction; #array_size]) -> Self {
let [#(#idents),*] = j;
MultiLocation::#variant( #(#idents),* )
}
}
}
})
.collect::<TokenStream>();

quote! {
impl From<()> for MultiLocation {
fn from(_: ()) -> Self {
MultiLocation::Null
}
}

impl From<Junction> for MultiLocation {
fn from(x: Junction) -> Self {
MultiLocation::X1(x)
}
}

impl From<[Junction; 0]> for MultiLocation {
fn from(_: [Junction; 0]) -> Self {
MultiLocation::Null
}
}

#from_tuples
}
}

fn generate_conversion_from_v1() -> TokenStream {
let match_variants = (0..8u8)
.map(|cur_num| {
let variant = format_ident!("X{}", cur_num + 1);
let idents = (1..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();

quote! {
crate::v1::Junctions::#variant( j0 #(, #idents)* ) => res
.pushed_with(Junction::from(j0))
#( .and_then(|res| res.pushed_with(Junction::from(#idents))) )*
.map_err(|_| ()),
}
})
.collect::<TokenStream>();

quote! {
impl TryFrom<crate::v1::MultiLocation> for MultiLocation {
type Error = ();
fn try_from(v1: crate::v1::MultiLocation) -> core::result::Result<Self, ()> {
let mut res = MultiLocation::Null;

for _ in 0..v1.parents {
res.push(Junction::Parent)?;
}

match v1.interior {
crate::v1::Junctions::Here => Ok(res),
#match_variants
}
}
}
}
}
17 changes: 17 additions & 0 deletions xcm/procedural/src/v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot 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.

// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.

pub mod multilocation;
Loading

0 comments on commit 4e0ab84

Please sign in to comment.