referrerpolicy=no-referrer-when-downgrade

xcm_procedural/
v3.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 multilocation {
24	use super::*;
25
26	pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
27		if !input.is_empty() {
28			return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
29		}
30
31		let from_tuples = generate_conversion_from_tuples(8, 8);
32
33		Ok(quote! {
34			#from_tuples
35		})
36	}
37
38	fn generate_conversion_from_tuples(max_junctions: usize, max_parents: usize) -> TokenStream {
39		let mut from_tuples = (0..=max_junctions)
40			.map(|num_junctions| {
41				let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
42				let idents =
43					(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
44				let array_size = num_junctions;
45				let interior = if num_junctions == 0 {
46					quote!(Junctions::Here)
47				} else {
48					quote! {
49						[#(#idents .into()),*].into()
50					}
51				};
52
53				let mut from_tuple = quote! {
54					impl< #(#types : Into<Junction>,)* > From<( Ancestor, #( #types ),* )> for MultiLocation {
55						fn from( ( Ancestor(parents), #(#idents),* ): ( Ancestor, #( #types ),* ) ) -> Self {
56							MultiLocation { parents, interior: #interior }
57						}
58					}
59
60					impl From<[Junction; #array_size]> for MultiLocation {
61						fn from(j: [Junction; #array_size]) -> Self {
62							let [#(#idents),*] = j;
63							MultiLocation { parents: 0, interior: #interior }
64						}
65					}
66				};
67
68				let from_parent_tuples = (0..=max_parents).map(|cur_parents| {
69					let parents =
70						(0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
71					let underscores =
72						(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
73
74					quote! {
75							impl< #(#types : Into<Junction>,)* > From<( #( #parents , )* #( #types , )* )> for MultiLocation {
76								fn from( ( #(#underscores,)* #(#idents,)* ): ( #(#parents,)* #(#types,)* ) ) -> Self {
77									Self { parents: #cur_parents as u8, interior: #interior }
78								}
79							}
80					}
81				});
82
83				from_tuple.extend(from_parent_tuples);
84				from_tuple
85			})
86			.collect::<TokenStream>();
87
88		let from_parent_junctions_tuples = (0..=max_parents).map(|cur_parents| {
89			let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
90			let underscores =
91				(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
92
93			quote! {
94				impl From<( #(#parents,)* Junctions )> for MultiLocation {
95					fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
96						MultiLocation { parents: #cur_parents as u8, interior: junctions }
97					}
98				}
99			}
100		});
101		from_tuples.extend(from_parent_junctions_tuples);
102
103		quote! {
104			impl From<(Ancestor, Junctions)> for MultiLocation {
105				fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
106					MultiLocation { parents, interior }
107				}
108			}
109
110			impl From<Junction> for MultiLocation {
111				fn from(x: Junction) -> Self {
112					MultiLocation { parents: 0, interior: [x].into() }
113				}
114			}
115
116			#from_tuples
117		}
118	}
119}
120
121pub mod junctions {
122	use super::*;
123
124	pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
125		if !input.is_empty() {
126			return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
127		}
128
129		// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
130		let from_v4 = generate_conversion_from_v4();
131		let from_tuples = generate_conversion_from_tuples(MAX_JUNCTIONS);
132
133		Ok(quote! {
134			#from_v4
135			#from_tuples
136		})
137	}
138
139	fn generate_conversion_from_tuples(max_junctions: usize) -> TokenStream {
140		(1..=max_junctions)
141			.map(|num_junctions| {
142				let idents =
143					(0..num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
144				let types = (0..num_junctions).map(|i| format_ident!("J{}", i)).collect::<Vec<_>>();
145
146				quote! {
147					impl<#(#types : Into<Junction>,)*> From<( #(#types,)* )> for Junctions {
148						fn from( ( #(#idents,)* ): ( #(#types,)* ) ) -> Self {
149							[#(#idents .into()),*].into()
150						}
151					}
152				}
153			})
154			.collect()
155	}
156
157	fn generate_conversion_from_v4() -> TokenStream {
158		let match_variants = (0..8u8)
159			.map(|current_number| {
160				let number_ancestors = current_number + 1;
161				let variant = format_ident!("X{}", number_ancestors);
162				let idents =
163					(0..=current_number).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
164				let convert = idents
165					.iter()
166					.map(|ident| {
167						quote! { let #ident = core::convert::TryInto::try_into(#ident.clone())?; }
168					})
169					.collect::<Vec<_>>();
170
171				quote! {
172					crate::v4::Junctions::#variant( junctions ) => {
173						let [#(#idents),*] = &*junctions;
174						#(#convert);*
175						[#(#idents),*].into()
176					},
177				}
178			})
179			.collect::<TokenStream>();
180
181		quote! {
182			impl core::convert::TryFrom<crate::v4::Junctions> for Junctions {
183				type Error = ();
184
185				fn try_from(mut new: crate::v4::Junctions) -> core::result::Result<Self, Self::Error> {
186					use Junctions::*;
187					Ok(match new {
188						crate::v4::Junctions::Here => Here,
189						#match_variants
190					})
191				}
192			}
193		}
194	}
195}