referrerpolicy=no-referrer-when-downgrade

xcm_procedural/
v5.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_v4 = generate_conversion_from_v4(MAX_JUNCTIONS);
135		let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
136
137		Ok(quote! {
138			#from_v4
139			#from_tuples
140		})
141	}
142
143	fn generate_conversion_from_tuples(max_junctions: usize) -> TokenStream {
144		(1..=max_junctions)
145			.map(|num_junctions| {
146				let idents =
147					(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
148				let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
149
150				quote! {
151					impl<#(#types : Into<Junction>,)*> From<( #(#types,)* )> for Junctions {
152						fn from( ( #(#idents,)* ): ( #(#types,)* ) ) -> Self {
153							[#(#idents .into()),*].into()
154						}
155					}
156				}
157			})
158			.collect()
159	}
160
161	fn generate_conversion_from_v4(max_junctions: usize) -> TokenStream {
162		let match_variants = (0..max_junctions)
163			.map(|cur_num| {
164				let num_ancestors = cur_num + 1;
165				let variant = format_ident!("X{}", num_ancestors);
166				let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
167				let convert = idents
168					.iter()
169					.enumerate()
170					.map(|(index, ident)| {
171						quote! { let #ident = core::convert::TryInto::try_into(slice[#index].clone())?; }
172					})
173					.collect::<Vec<_>>();
174
175				quote! {
176					crate::v4::Junctions::#variant( arc ) => {
177						let slice = &arc[..];
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::v4::Junctions> for Junctions {
188				type Error = ();
189				fn try_from(mut old: crate::v4::Junctions) -> core::result::Result<Self, ()> {
190					Ok(match old {
191					 crate::v4::Junctions::Here => Junctions::Here,
192					 #match_variants
193					})
194				}
195			}
196		}
197	}
198}