xcm_procedural/
v2.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
21pub mod multilocation {
22	use super::*;
23
24	pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
25		if !input.is_empty() {
26			return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
27		}
28
29		// Support up to 8 Parents in a tuple, assuming that most use cases don't go past 8 parents.
30		let from_tuples = generate_conversion_from_tuples(8);
31		let from_v3 = generate_conversion_from_v3();
32
33		Ok(quote! {
34			#from_tuples
35			#from_v3
36		})
37	}
38
39	fn generate_conversion_from_tuples(max_parents: u8) -> TokenStream {
40		let mut from_tuples = (0..8usize)
41			.map(|num_junctions| {
42				let junctions =
43					(0..=num_junctions).map(|_| format_ident!("Junction")).collect::<Vec<_>>();
44				let idents =
45					(0..=num_junctions).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
46				let variant = &format_ident!("X{}", num_junctions + 1);
47				let array_size = num_junctions + 1;
48
49				let mut from_tuple = quote! {
50					impl From<( #(#junctions,)* )> for MultiLocation {
51						fn from( ( #(#idents,)* ): ( #(#junctions,)* ) ) -> Self {
52							MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) }
53						}
54					}
55
56					impl From<(u8, #(#junctions),*)> for MultiLocation {
57						fn from( ( parents, #(#idents),* ): (u8, #(#junctions),* ) ) -> Self {
58							MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) }
59						}
60					}
61
62					impl From<(Ancestor, #(#junctions),*)> for MultiLocation {
63						fn from( ( Ancestor(parents), #(#idents),* ): (Ancestor, #(#junctions),* ) ) -> Self {
64							MultiLocation { parents, interior: Junctions::#variant( #(#idents),* ) }
65						}
66					}
67
68					impl From<[Junction; #array_size]> for MultiLocation {
69						fn from(j: [Junction; #array_size]) -> Self {
70							let [#(#idents),*] = j;
71							MultiLocation { parents: 0, interior: Junctions::#variant( #(#idents),* ) }
72						}
73					}
74				};
75
76				let from_parent_tuples = (1..=max_parents).map(|cur_parents| {
77					let parents =
78						(0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
79					let underscores =
80						(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
81
82					quote! {
83						impl From<( #(#parents,)* #(#junctions),* )> for MultiLocation {
84							fn from( (#(#underscores,)* #(#idents),*): ( #(#parents,)* #(#junctions),* ) ) -> Self {
85								MultiLocation { parents: #cur_parents, interior: Junctions::#variant( #(#idents),* ) }
86							}
87						}
88					}
89				});
90
91				from_tuple.extend(from_parent_tuples);
92				from_tuple
93			})
94			.collect::<TokenStream>();
95
96		let from_parent_junctions_tuples = (1..=max_parents).map(|cur_parents| {
97			let parents = (0..cur_parents).map(|_| format_ident!("Parent")).collect::<Vec<_>>();
98			let underscores =
99				(0..cur_parents).map(|_| Token![_](Span::call_site())).collect::<Vec<_>>();
100
101			quote! {
102				impl From<( #(#parents,)* Junctions )> for MultiLocation {
103					fn from( (#(#underscores,)* junctions): ( #(#parents,)* Junctions ) ) -> Self {
104						MultiLocation { parents: #cur_parents, interior: junctions }
105					}
106				}
107			}
108		});
109		from_tuples.extend(from_parent_junctions_tuples);
110
111		quote! {
112			impl From<Junctions> for MultiLocation {
113				fn from(junctions: Junctions) -> Self {
114					MultiLocation { parents: 0, interior: junctions }
115				}
116			}
117
118			impl From<(u8, Junctions)> for MultiLocation {
119				fn from((parents, interior): (u8, Junctions)) -> Self {
120					MultiLocation { parents, interior }
121				}
122			}
123
124			impl From<(Ancestor, Junctions)> for MultiLocation {
125				fn from((Ancestor(parents), interior): (Ancestor, Junctions)) -> Self {
126					MultiLocation { parents, interior }
127				}
128			}
129
130			impl From<()> for MultiLocation {
131				fn from(_: ()) -> Self {
132					MultiLocation { parents: 0, interior: Junctions::Here }
133				}
134			}
135
136			impl From<(u8,)> for MultiLocation {
137				fn from((parents,): (u8,)) -> Self {
138					MultiLocation { parents, interior: Junctions::Here }
139				}
140			}
141
142			impl From<Junction> for MultiLocation {
143				fn from(x: Junction) -> Self {
144					MultiLocation { parents: 0, interior: Junctions::X1(x) }
145				}
146			}
147
148			impl From<[Junction; 0]> for MultiLocation {
149				fn from(_: [Junction; 0]) -> Self {
150					MultiLocation { parents: 0, interior: Junctions::Here }
151				}
152			}
153
154			#from_tuples
155		}
156	}
157
158	fn generate_conversion_from_v3() -> TokenStream {
159		let match_variants = (0..8u8)
160			.map(|cur_num| {
161				let num_ancestors = cur_num + 1;
162				let variant = format_ident!("X{}", num_ancestors);
163				let idents = (0..=cur_num).map(|i| format_ident!("j{}", i)).collect::<Vec<_>>();
164
165				quote! {
166					crate::v3::Junctions::#variant( #(#idents),* ) =>
167						#variant( #( core::convert::TryInto::try_into(#idents)? ),* ),
168				}
169			})
170			.collect::<TokenStream>();
171
172		quote! {
173			impl core::convert::TryFrom<crate::v3::Junctions> for Junctions {
174				type Error = ();
175				fn try_from(mut new: crate::v3::Junctions) -> core::result::Result<Self, ()> {
176					use Junctions::*;
177					Ok(match new {
178						crate::v3::Junctions::Here => Here,
179						#match_variants
180					})
181				}
182			}
183		}
184	}
185}
186
187pub mod junctions {
188	use super::*;
189
190	pub fn generate_conversion_functions(input: proc_macro::TokenStream) -> Result<TokenStream> {
191		if !input.is_empty() {
192			return Err(syn::Error::new(Span::call_site(), "No arguments expected"))
193		}
194
195		let from_slice_syntax = generate_conversion_from_slice_syntax();
196
197		Ok(quote! {
198			#from_slice_syntax
199		})
200	}
201
202	fn generate_conversion_from_slice_syntax() -> TokenStream {
203		quote! {
204			macro_rules! impl_junction {
205				($count:expr, $variant:ident, ($($index:literal),+)) => {
206					/// Additional helper for building junctions
207					/// Useful for converting to future XCM versions
208					impl From<[Junction; $count]> for Junctions {
209						fn from(junctions: [Junction; $count]) -> Self {
210							Self::$variant($(junctions[$index].clone()),*)
211						}
212					}
213				};
214			}
215
216			impl_junction!(1, X1, (0));
217			impl_junction!(2, X2, (0, 1));
218			impl_junction!(3, X3, (0, 1, 2));
219			impl_junction!(4, X4, (0, 1, 2, 3));
220			impl_junction!(5, X5, (0, 1, 2, 3, 4));
221			impl_junction!(6, X6, (0, 1, 2, 3, 4, 5));
222			impl_junction!(7, X7, (0, 1, 2, 3, 4, 5, 6));
223			impl_junction!(8, X8, (0, 1, 2, 3, 4, 5, 6, 7));
224		}
225	}
226}