referrerpolicy=no-referrer-when-downgrade

xcm_procedural/
v4.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17use proc_macro2::{Span, TokenStream};
18use quote::{format_ident, quote};
19use syn::{Result, Token};
20
21const MAX_JUNCTIONS: usize = 8;
22
23pub mod location {
24	use super::*;
25
26	/// Generates conversion functions from other types to the `Location` type:
27	/// - [PalletInstance(50), GeneralIndex(1984)].into()
28	/// - (Parent, Parachain(1000), AccountId32 { .. }).into()
29	pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
30		if !input.is_empty() {
31			return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
32		}
33
34		let from_tuples = generate_conversion_from_tuples(8, 8);
35
36		Ok(quote! {
37			#from_tuples
38		})
39	}
40
41	fn generate_conversion_from_tuples(max_junctions: usize, max_parents: usize) -> TokenStream {
42		let mut from_tuples = (0..=max_junctions)
43			.map(|num_junctions| {
44				let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
45				let idents =
46					(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
47				let array_size = num_junctions;
48				let interior = if num_junctions == 0 {
49					quote!(Junctions::Here)
50				} else {
51					let variant = format_ident!("X{}", num_junctions);
52					quote! {
53						Junctions::#variant( alloc::sync::Arc::new( [#(#idents .into()),*] ) )
54					}
55				};
56
57				let mut from_tuple = quote! {
58					impl< #(#types : Into<Junction>,)* > From<( Ancestor, #( #types ),* )> for Location {
59						fn from( ( Ancestor(parents), #(#idents),* ): ( Ancestor, #( #types ),* ) ) -> Self {
60							Location { parents, interior: #interior }
61						}
62					}
63
64					impl From<[Junction; #array_size]> for Location {
65						fn from(j: [Junction; #array_size]) -> Self {
66							let [#(#idents),*] = j;
67							Location { parents: 0, interior: #interior }
68						}
69					}
70				};
71
72				let from_parent_tuples = (0..=max_parents).map(|cur_parents| {
73					let parents =
74						(0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
75					let underscores =
76						(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
77
78					quote! {
79						impl< #(#types : Into<Junction>,)* > From<( #( #parents , )* #( #types , )* )> for Location {
80							fn from( ( #(#underscores,)* #(#idents,)* ): ( #(#parents,)* #(#types,)* ) ) -> Self {
81								Self { parents: #cur_parents as u8, interior: #interior }
82							}
83						}
84					}
85				});
86
87				from_tuple.extend(from_parent_tuples);
88				from_tuple
89			})
90			.collect::<TokenStream>();
91
92		let from_parent_junctions_tuples = (0..=max_parents).map(|cur_parents| {
93			let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
94			let underscores =
95				(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
96
97			quote! {
98				impl From<( #(#parents,)* Junctions )> for Location {
99					fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
100						Location { parents: #cur_parents as u8, interior: junctions }
101					}
102				}
103			}
104		});
105		from_tuples.extend(from_parent_junctions_tuples);
106
107		quote! {
108			impl From<(Ancestor, Junctions)> for Location {
109				fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
110					Location { parents, interior }
111				}
112			}
113
114			impl From<Junction> for Location {
115				fn from(x: Junction) -> Self {
116					Location { parents: 0, interior: [x].into() }
117				}
118			}
119
120			#from_tuples
121		}
122	}
123}
124
125pub mod junctions {
126	use super::*;
127
128	pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
129		if !input.is_empty() {
130			return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
131		}
132
133		// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
134		let from_v3 = generate_conversion_from_v3(MAX_JUNCTIONS);
135		let from_v5 = generate_conversion_from_v5(MAX_JUNCTIONS);
136		let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
137
138		Ok(quote! {
139			#from_v3
140			#from_v5
141			#from_tuples
142		})
143	}
144
145	fn generate_conversion_from_tuples(max_junctions: usize) -> TokenStream {
146		(1..=max_junctions)
147			.map(|num_junctions| {
148				let idents =
149					(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
150				let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
151
152				quote! {
153					impl<#(#types : Into<Junction>,)*> From<( #(#types,)* )> for Junctions {
154						fn from( ( #(#idents,)* ): ( #(#types,)* ) ) -> Self {
155							[#(#idents .into()),*].into()
156						}
157					}
158				}
159			})
160			.collect()
161	}
162
163	fn generate_conversion_from_v3(max_junctions: usize) -> TokenStream {
164		let match_variants = (0..max_junctions)
165			.map(|cur_num| {
166				let num_ancestors = cur_num + 1;
167				let variant = format_ident!("X{}", num_ancestors);
168				let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
169				let convert = idents
170					.iter()
171					.map(|ident| {
172						quote! { let #ident = core::convert::TryInto::try_into(#ident.clone())?; }
173					})
174					.collect::<Vec<_>>();
175
176				quote! {
177					crate::v3::Junctions::#variant( #(#idents),* ) => {
178						#(#convert);*;
179						let junctions: Junctions = [#(#idents),*].into();
180						junctions
181					},
182				}
183			})
184			.collect::<TokenStream>();
185
186		quote! {
187			impl core::convert::TryFrom<crate::v3::Junctions> for Junctions {
188				type Error = ();
189				fn try_from(mut old: crate::v3::Junctions) -> core::result::Result<Self, ()> {
190					Ok(match old {
191					 crate::v3::Junctions::Here => Junctions::Here,
192					 #match_variants
193					})
194				}
195			}
196		}
197	}
198
199	fn generate_conversion_from_v5(max_junctions: usize) -> TokenStream {
200		let match_variants = (0..max_junctions)
201			.map(|current_number| {
202				let number_ancestors = current_number + 1;
203				let variant = format_ident!("X{}", number_ancestors);
204				let idents =
205					(0..=current_number).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
206				let convert = idents
207					.iter()
208					.map(|ident| {
209						quote! { let #ident = core::convert::TryInto::try_into(#ident.clone())?; }
210					})
211					.collect::<Vec<_>>();
212
213				quote! {
214					crate::v5::Junctions::#variant( junctions ) => {
215						let [#(#idents),*] = &*junctions;
216						#(#convert);*
217						[#(#idents),*].into()
218					},
219				}
220			})
221			.collect::<TokenStream>();
222
223		quote! {
224			impl core::convert::TryFrom<crate::v5::Junctions> for Junctions {
225				type Error = ();
226
227				fn try_from(mut new: crate::v5::Junctions) -> core::result::Result<Self, Self::Error> {
228					use Junctions::*;
229					Ok(match new {
230						crate::v5::Junctions::Here => Here,
231						#match_variants
232					})
233				}
234			}
235		}
236	}
237}