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

            
17
//! XCM `Junctions`/`InteriorMultiLocation` datatype.
18

            
19
use super::{Junction, MultiLocation, NetworkId};
20
use codec::{Decode, Encode, MaxEncodedLen};
21
use core::{mem, result};
22
use scale_info::TypeInfo;
23

            
24
/// Maximum number of `Junction`s that a `Junctions` can contain.
25
pub(crate) const MAX_JUNCTIONS: usize = 8;
26

            
27
/// Non-parent junctions that can be constructed, up to the length of 8. This specific `Junctions`
28
/// implementation uses a Rust `enum` in order to make pattern matching easier.
29
///
30
/// Parent junctions cannot be constructed with this type. Refer to `MultiLocation` for
31
/// instructions on constructing parent junctions.
32
#[derive(
33
	Copy,
34
	Clone,
35
	Eq,
36
	PartialEq,
37
	Ord,
38
	PartialOrd,
39
	Encode,
40
354
	Decode,
41
	Debug,
42
	TypeInfo,
43
	MaxEncodedLen,
44
	serde::Serialize,
45
	serde::Deserialize,
46
)]
47
#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
48
#[scale_info(replace_segment("staging_xcm", "xcm"))]
49
pub enum Junctions {
50
22455
	/// The interpreting consensus system.
51
22455
	Here,
52
2541
	/// A relative path comprising 1 junction.
53
2541
	X1(Junction),
54
270
	/// A relative path comprising 2 junctions.
55
270
	X2(Junction, Junction),
56
513
	/// A relative path comprising 3 junctions.
57
513
	X3(Junction, Junction, Junction),
58
645
	/// A relative path comprising 4 junctions.
59
645
	X4(Junction, Junction, Junction, Junction),
60
405
	/// A relative path comprising 5 junctions.
61
405
	X5(Junction, Junction, Junction, Junction, Junction),
62
732
	/// A relative path comprising 6 junctions.
63
732
	X6(Junction, Junction, Junction, Junction, Junction, Junction),
64
210
	/// A relative path comprising 7 junctions.
65
210
	X7(Junction, Junction, Junction, Junction, Junction, Junction, Junction),
66
228
	/// A relative path comprising 8 junctions.
67
228
	X8(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction),
68
}
69

            
70
macro_rules! impl_junction {
71
	($count:expr, $variant:ident, ($($index:literal),+)) => {
72
		/// Additional helper for building junctions
73
		/// Useful for converting to future XCM versions
74
		impl From<[Junction; $count]> for Junctions {
75
			fn from(junctions: [Junction; $count]) -> Self {
76
				Self::$variant($(junctions[$index]),*)
77
			}
78
		}
79
	};
80
}
81

            
82
impl_junction!(1, X1, (0));
83
impl_junction!(2, X2, (0, 1));
84
impl_junction!(3, X3, (0, 1, 2));
85
impl_junction!(4, X4, (0, 1, 2, 3));
86
impl_junction!(5, X5, (0, 1, 2, 3, 4));
87
impl_junction!(6, X6, (0, 1, 2, 3, 4, 5));
88
impl_junction!(7, X7, (0, 1, 2, 3, 4, 5, 6));
89
impl_junction!(8, X8, (0, 1, 2, 3, 4, 5, 6, 7));
90

            
91
pub struct JunctionsIterator(Junctions);
92
impl Iterator for JunctionsIterator {
93
	type Item = Junction;
94
	fn next(&mut self) -> Option<Junction> {
95
		self.0.take_first()
96
	}
97
}
98

            
99
impl DoubleEndedIterator for JunctionsIterator {
100
	fn next_back(&mut self) -> Option<Junction> {
101
		self.0.take_last()
102
	}
103
}
104

            
105
pub struct JunctionsRefIterator<'a> {
106
	junctions: &'a Junctions,
107
	next: usize,
108
	back: usize,
109
}
110

            
111
impl<'a> Iterator for JunctionsRefIterator<'a> {
112
	type Item = &'a Junction;
113
	fn next(&mut self) -> Option<&'a Junction> {
114
		if self.next.saturating_add(self.back) >= self.junctions.len() {
115
			return None
116
		}
117

            
118
		let result = self.junctions.at(self.next);
119
		self.next += 1;
120
		result
121
	}
122
}
123

            
124
impl<'a> DoubleEndedIterator for JunctionsRefIterator<'a> {
125
	fn next_back(&mut self) -> Option<&'a Junction> {
126
		let next_back = self.back.saturating_add(1);
127
		// checked_sub here, because if the result is less than 0, we end iteration
128
		let index = self.junctions.len().checked_sub(next_back)?;
129
		if self.next > index {
130
			return None
131
		}
132
		self.back = next_back;
133

            
134
		self.junctions.at(index)
135
	}
136
}
137
impl<'a> IntoIterator for &'a Junctions {
138
	type Item = &'a Junction;
139
	type IntoIter = JunctionsRefIterator<'a>;
140
	fn into_iter(self) -> Self::IntoIter {
141
		JunctionsRefIterator { junctions: self, next: 0, back: 0 }
142
	}
143
}
144

            
145
impl IntoIterator for Junctions {
146
	type Item = Junction;
147
	type IntoIter = JunctionsIterator;
148
	fn into_iter(self) -> Self::IntoIter {
149
		JunctionsIterator(self)
150
	}
151
}
152

            
153
impl Junctions {
154
	/// Convert `self` into a `MultiLocation` containing 0 parents.
155
	///
156
	/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
157
	pub const fn into_location(self) -> MultiLocation {
158
		MultiLocation { parents: 0, interior: self }
159
	}
160

            
161
	/// Convert `self` into a `MultiLocation` containing `n` parents.
162
	///
163
	/// Similar to `Self::into_location`, with the added ability to specify the number of parent
164
	/// junctions.
165
	pub const fn into_exterior(self, n: u8) -> MultiLocation {
166
		MultiLocation { parents: n, interior: self }
167
	}
168

            
169
	/// Remove the `NetworkId` value in any `Junction`s.
170
	pub fn remove_network_id(&mut self) {
171
		self.for_each_mut(Junction::remove_network_id);
172
	}
173

            
174
	/// Treating `self` as the universal context, return the location of the local consensus system
175
	/// from the point of view of the given `target`.
176
	pub fn invert_target(mut self, target: &MultiLocation) -> Result<MultiLocation, ()> {
177
		let mut junctions = Self::Here;
178
		for _ in 0..target.parent_count() {
179
			junctions = junctions
180
				.pushed_front_with(self.take_last().unwrap_or(Junction::OnlyChild))
181
				.map_err(|_| ())?;
182
		}
183
		let parents = target.interior().len() as u8;
184
		Ok(MultiLocation::new(parents, junctions))
185
	}
186

            
187
	/// Execute a function `f` on every junction. We use this since we cannot implement a mutable
188
	/// `Iterator` without unsafe code.
189
	pub fn for_each_mut(&mut self, mut x: impl FnMut(&mut Junction)) {
190
		match self {
191
			Junctions::Here => {},
192
			Junctions::X1(a) => {
193
				x(a);
194
			},
195
			Junctions::X2(a, b) => {
196
				x(a);
197
				x(b);
198
			},
199
			Junctions::X3(a, b, c) => {
200
				x(a);
201
				x(b);
202
				x(c);
203
			},
204
			Junctions::X4(a, b, c, d) => {
205
				x(a);
206
				x(b);
207
				x(c);
208
				x(d);
209
			},
210
			Junctions::X5(a, b, c, d, e) => {
211
				x(a);
212
				x(b);
213
				x(c);
214
				x(d);
215
				x(e);
216
			},
217
			Junctions::X6(a, b, c, d, e, f) => {
218
				x(a);
219
				x(b);
220
				x(c);
221
				x(d);
222
				x(e);
223
				x(f);
224
			},
225
			Junctions::X7(a, b, c, d, e, f, g) => {
226
				x(a);
227
				x(b);
228
				x(c);
229
				x(d);
230
				x(e);
231
				x(f);
232
				x(g);
233
			},
234
			Junctions::X8(a, b, c, d, e, f, g, h) => {
235
				x(a);
236
				x(b);
237
				x(c);
238
				x(d);
239
				x(e);
240
				x(f);
241
				x(g);
242
				x(h);
243
			},
244
		}
245
	}
246

            
247
	/// Extract the network ID treating this value as a universal location.
248
	///
249
	/// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate
250
	/// that this value is not a universal location.
251
	pub fn global_consensus(&self) -> Result<NetworkId, ()> {
252
		if let Some(Junction::GlobalConsensus(network)) = self.first() {
253
			Ok(*network)
254
		} else {
255
			Err(())
256
		}
257
	}
258

            
259
	/// Extract the network ID and the interior consensus location, treating this value as a
260
	/// universal location.
261
	///
262
	/// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate
263
	/// that this value is not a universal location.
264
	pub fn split_global(self) -> Result<(NetworkId, Junctions), ()> {
265
		match self.split_first() {
266
			(location, Some(Junction::GlobalConsensus(network))) => Ok((network, location)),
267
			_ => return Err(()),
268
		}
269
	}
270

            
271
	/// Treat `self` as a universal location and the context of `relative`, returning the universal
272
	/// location of relative.
273
	///
274
	/// This will return an error if `relative` has as many (or more) parents than there are
275
	/// junctions in `self`, implying that relative refers into a different global consensus.
276
	pub fn within_global(mut self, relative: MultiLocation) -> Result<Self, ()> {
277
		if self.len() <= relative.parents as usize {
278
			return Err(())
279
		}
280
		for _ in 0..relative.parents {
281
			self.take_last();
282
		}
283
		for j in relative.interior {
284
			self.push(j).map_err(|_| ())?;
285
		}
286
		Ok(self)
287
	}
288

            
289
	/// Consumes `self` and returns how `viewer` would address it locally.
290
	pub fn relative_to(mut self, viewer: &Junctions) -> MultiLocation {
291
		let mut i = 0;
292
		while match (self.first(), viewer.at(i)) {
293
			(Some(x), Some(y)) => x == y,
294
			_ => false,
295
		} {
296
			self = self.split_first().0;
297
			// NOTE: Cannot overflow as loop can only iterate at most `MAX_JUNCTIONS` times.
298
			i += 1;
299
		}
300
		// AUDIT NOTES:
301
		// - above loop ensures that `i <= viewer.len()`.
302
		// - `viewer.len()` is at most `MAX_JUNCTIONS`, so won't overflow a `u8`.
303
		MultiLocation { parents: (viewer.len() - i) as u8, interior: self }
304
	}
305

            
306
	/// Returns first junction, or `None` if the location is empty.
307
	pub fn first(&self) -> Option<&Junction> {
308
		match &self {
309
			Junctions::Here => None,
310
			Junctions::X1(ref a) => Some(a),
311
			Junctions::X2(ref a, ..) => Some(a),
312
			Junctions::X3(ref a, ..) => Some(a),
313
			Junctions::X4(ref a, ..) => Some(a),
314
			Junctions::X5(ref a, ..) => Some(a),
315
			Junctions::X6(ref a, ..) => Some(a),
316
			Junctions::X7(ref a, ..) => Some(a),
317
			Junctions::X8(ref a, ..) => Some(a),
318
		}
319
	}
320

            
321
	/// Returns last junction, or `None` if the location is empty.
322
	pub fn last(&self) -> Option<&Junction> {
323
		match &self {
324
			Junctions::Here => None,
325
			Junctions::X1(ref a) => Some(a),
326
			Junctions::X2(.., ref a) => Some(a),
327
			Junctions::X3(.., ref a) => Some(a),
328
			Junctions::X4(.., ref a) => Some(a),
329
			Junctions::X5(.., ref a) => Some(a),
330
			Junctions::X6(.., ref a) => Some(a),
331
			Junctions::X7(.., ref a) => Some(a),
332
			Junctions::X8(.., ref a) => Some(a),
333
		}
334
	}
335

            
336
	/// Splits off the first junction, returning the remaining suffix (first item in tuple) and the
337
	/// first element (second item in tuple) or `None` if it was empty.
338
	pub fn split_first(self) -> (Junctions, Option<Junction>) {
339
		match self {
340
			Junctions::Here => (Junctions::Here, None),
341
			Junctions::X1(a) => (Junctions::Here, Some(a)),
342
			Junctions::X2(a, b) => (Junctions::X1(b), Some(a)),
343
			Junctions::X3(a, b, c) => (Junctions::X2(b, c), Some(a)),
344
			Junctions::X4(a, b, c, d) => (Junctions::X3(b, c, d), Some(a)),
345
			Junctions::X5(a, b, c, d, e) => (Junctions::X4(b, c, d, e), Some(a)),
346
			Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(b, c, d, e, f), Some(a)),
347
			Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(b, c, d, e, f, g), Some(a)),
348
			Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(b, c, d, e, f, g, h), Some(a)),
349
		}
350
	}
351

            
352
	/// Splits off the last junction, returning the remaining prefix (first item in tuple) and the
353
	/// last element (second item in tuple) or `None` if it was empty.
354
	pub fn split_last(self) -> (Junctions, Option<Junction>) {
355
		match self {
356
			Junctions::Here => (Junctions::Here, None),
357
			Junctions::X1(a) => (Junctions::Here, Some(a)),
358
			Junctions::X2(a, b) => (Junctions::X1(a), Some(b)),
359
			Junctions::X3(a, b, c) => (Junctions::X2(a, b), Some(c)),
360
			Junctions::X4(a, b, c, d) => (Junctions::X3(a, b, c), Some(d)),
361
			Junctions::X5(a, b, c, d, e) => (Junctions::X4(a, b, c, d), Some(e)),
362
			Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(a, b, c, d, e), Some(f)),
363
			Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(a, b, c, d, e, f), Some(g)),
364
			Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(a, b, c, d, e, f, g), Some(h)),
365
		}
366
	}
367

            
368
	/// Removes the first element from `self`, returning it (or `None` if it was empty).
369
	pub fn take_first(&mut self) -> Option<Junction> {
370
		let mut d = Junctions::Here;
371
		mem::swap(&mut *self, &mut d);
372
		let (tail, head) = d.split_first();
373
		*self = tail;
374
		head
375
	}
376

            
377
	/// Removes the last element from `self`, returning it (or `None` if it was empty).
378
	pub fn take_last(&mut self) -> Option<Junction> {
379
		let mut d = Junctions::Here;
380
		mem::swap(&mut *self, &mut d);
381
		let (head, tail) = d.split_last();
382
		*self = head;
383
		tail
384
	}
385

            
386
	/// Mutates `self` to be appended with `new` or returns an `Err` with `new` if would overflow.
387
	pub fn push(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
388
		let new = new.into();
389
		let mut dummy = Junctions::Here;
390
		mem::swap(self, &mut dummy);
391
		match dummy.pushed_with(new) {
392
			Ok(s) => {
393
				*self = s;
394
				Ok(())
395
			},
396
			Err((s, j)) => {
397
				*self = s;
398
				Err(j)
399
			},
400
		}
401
	}
402

            
403
	/// Mutates `self` to be prepended with `new` or returns an `Err` with `new` if would overflow.
404
	pub fn push_front(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
405
		let new = new.into();
406
		let mut dummy = Junctions::Here;
407
		mem::swap(self, &mut dummy);
408
		match dummy.pushed_front_with(new) {
409
			Ok(s) => {
410
				*self = s;
411
				Ok(())
412
			},
413
			Err((s, j)) => {
414
				*self = s;
415
				Err(j)
416
			},
417
		}
418
	}
419

            
420
	/// Consumes `self` and returns a `Junctions` suffixed with `new`, or an `Err` with the
421
	/// original value of `self` and `new` in case of overflow.
422
	pub fn pushed_with(self, new: impl Into<Junction>) -> result::Result<Self, (Self, Junction)> {
423
		let new = new.into();
424
		Ok(match self {
425
			Junctions::Here => Junctions::X1(new),
426
			Junctions::X1(a) => Junctions::X2(a, new),
427
			Junctions::X2(a, b) => Junctions::X3(a, b, new),
428
			Junctions::X3(a, b, c) => Junctions::X4(a, b, c, new),
429
			Junctions::X4(a, b, c, d) => Junctions::X5(a, b, c, d, new),
430
			Junctions::X5(a, b, c, d, e) => Junctions::X6(a, b, c, d, e, new),
431
			Junctions::X6(a, b, c, d, e, f) => Junctions::X7(a, b, c, d, e, f, new),
432
			Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(a, b, c, d, e, f, g, new),
433
			s => Err((s, new))?,
434
		})
435
	}
436

            
437
	/// Consumes `self` and returns a `Junctions` prefixed with `new`, or an `Err` with the
438
	/// original value of `self` and `new` in case of overflow.
439
	pub fn pushed_front_with(
440
		self,
441
		new: impl Into<Junction>,
442
	) -> result::Result<Self, (Self, Junction)> {
443
		let new = new.into();
444
		Ok(match self {
445
			Junctions::Here => Junctions::X1(new),
446
			Junctions::X1(a) => Junctions::X2(new, a),
447
			Junctions::X2(a, b) => Junctions::X3(new, a, b),
448
			Junctions::X3(a, b, c) => Junctions::X4(new, a, b, c),
449
			Junctions::X4(a, b, c, d) => Junctions::X5(new, a, b, c, d),
450
			Junctions::X5(a, b, c, d, e) => Junctions::X6(new, a, b, c, d, e),
451
			Junctions::X6(a, b, c, d, e, f) => Junctions::X7(new, a, b, c, d, e, f),
452
			Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(new, a, b, c, d, e, f, g),
453
			s => Err((s, new))?,
454
		})
455
	}
456

            
457
	/// Mutate `self` so that it is suffixed with `suffix`.
458
	///
459
	/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
460
	///
461
	/// # Example
462
	/// ```rust
463
	/// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation};
464
	/// let mut m = X1(Parachain(21));
465
	/// assert_eq!(m.append_with(X1(PalletInstance(3))), Ok(()));
466
	/// assert_eq!(m, X2(Parachain(21), PalletInstance(3)));
467
	/// ```
468
	pub fn append_with(&mut self, suffix: impl Into<Junctions>) -> Result<(), Junctions> {
469
		let suffix = suffix.into();
470
		if self.len().saturating_add(suffix.len()) > MAX_JUNCTIONS {
471
			return Err(suffix)
472
		}
473
		for j in suffix.into_iter() {
474
			self.push(j).expect("Already checked the sum of the len()s; qed")
475
		}
476
		Ok(())
477
	}
478

            
479
	/// Returns the number of junctions in `self`.
480
	pub const fn len(&self) -> usize {
481
		match &self {
482
			Junctions::Here => 0,
483
			Junctions::X1(..) => 1,
484
			Junctions::X2(..) => 2,
485
			Junctions::X3(..) => 3,
486
			Junctions::X4(..) => 4,
487
			Junctions::X5(..) => 5,
488
			Junctions::X6(..) => 6,
489
			Junctions::X7(..) => 7,
490
			Junctions::X8(..) => 8,
491
		}
492
	}
493

            
494
	/// Returns the junction at index `i`, or `None` if the location doesn't contain that many
495
	/// elements.
496
	pub fn at(&self, i: usize) -> Option<&Junction> {
497
		Some(match (i, self) {
498
			(0, Junctions::X1(ref a)) => a,
499
			(0, Junctions::X2(ref a, ..)) => a,
500
			(0, Junctions::X3(ref a, ..)) => a,
501
			(0, Junctions::X4(ref a, ..)) => a,
502
			(0, Junctions::X5(ref a, ..)) => a,
503
			(0, Junctions::X6(ref a, ..)) => a,
504
			(0, Junctions::X7(ref a, ..)) => a,
505
			(0, Junctions::X8(ref a, ..)) => a,
506
			(1, Junctions::X2(_, ref a)) => a,
507
			(1, Junctions::X3(_, ref a, ..)) => a,
508
			(1, Junctions::X4(_, ref a, ..)) => a,
509
			(1, Junctions::X5(_, ref a, ..)) => a,
510
			(1, Junctions::X6(_, ref a, ..)) => a,
511
			(1, Junctions::X7(_, ref a, ..)) => a,
512
			(1, Junctions::X8(_, ref a, ..)) => a,
513
			(2, Junctions::X3(_, _, ref a)) => a,
514
			(2, Junctions::X4(_, _, ref a, ..)) => a,
515
			(2, Junctions::X5(_, _, ref a, ..)) => a,
516
			(2, Junctions::X6(_, _, ref a, ..)) => a,
517
			(2, Junctions::X7(_, _, ref a, ..)) => a,
518
			(2, Junctions::X8(_, _, ref a, ..)) => a,
519
			(3, Junctions::X4(_, _, _, ref a)) => a,
520
			(3, Junctions::X5(_, _, _, ref a, ..)) => a,
521
			(3, Junctions::X6(_, _, _, ref a, ..)) => a,
522
			(3, Junctions::X7(_, _, _, ref a, ..)) => a,
523
			(3, Junctions::X8(_, _, _, ref a, ..)) => a,
524
			(4, Junctions::X5(_, _, _, _, ref a)) => a,
525
			(4, Junctions::X6(_, _, _, _, ref a, ..)) => a,
526
			(4, Junctions::X7(_, _, _, _, ref a, ..)) => a,
527
			(4, Junctions::X8(_, _, _, _, ref a, ..)) => a,
528
			(5, Junctions::X6(_, _, _, _, _, ref a)) => a,
529
			(5, Junctions::X7(_, _, _, _, _, ref a, ..)) => a,
530
			(5, Junctions::X8(_, _, _, _, _, ref a, ..)) => a,
531
			(6, Junctions::X7(_, _, _, _, _, _, ref a)) => a,
532
			(6, Junctions::X8(_, _, _, _, _, _, ref a, ..)) => a,
533
			(7, Junctions::X8(_, _, _, _, _, _, _, ref a)) => a,
534
			_ => return None,
535
		})
536
	}
537

            
538
	/// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't
539
	/// contain that many elements.
540
	pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
541
		Some(match (i, self) {
542
			(0, Junctions::X1(ref mut a)) => a,
543
			(0, Junctions::X2(ref mut a, ..)) => a,
544
			(0, Junctions::X3(ref mut a, ..)) => a,
545
			(0, Junctions::X4(ref mut a, ..)) => a,
546
			(0, Junctions::X5(ref mut a, ..)) => a,
547
			(0, Junctions::X6(ref mut a, ..)) => a,
548
			(0, Junctions::X7(ref mut a, ..)) => a,
549
			(0, Junctions::X8(ref mut a, ..)) => a,
550
			(1, Junctions::X2(_, ref mut a)) => a,
551
			(1, Junctions::X3(_, ref mut a, ..)) => a,
552
			(1, Junctions::X4(_, ref mut a, ..)) => a,
553
			(1, Junctions::X5(_, ref mut a, ..)) => a,
554
			(1, Junctions::X6(_, ref mut a, ..)) => a,
555
			(1, Junctions::X7(_, ref mut a, ..)) => a,
556
			(1, Junctions::X8(_, ref mut a, ..)) => a,
557
			(2, Junctions::X3(_, _, ref mut a)) => a,
558
			(2, Junctions::X4(_, _, ref mut a, ..)) => a,
559
			(2, Junctions::X5(_, _, ref mut a, ..)) => a,
560
			(2, Junctions::X6(_, _, ref mut a, ..)) => a,
561
			(2, Junctions::X7(_, _, ref mut a, ..)) => a,
562
			(2, Junctions::X8(_, _, ref mut a, ..)) => a,
563
			(3, Junctions::X4(_, _, _, ref mut a)) => a,
564
			(3, Junctions::X5(_, _, _, ref mut a, ..)) => a,
565
			(3, Junctions::X6(_, _, _, ref mut a, ..)) => a,
566
			(3, Junctions::X7(_, _, _, ref mut a, ..)) => a,
567
			(3, Junctions::X8(_, _, _, ref mut a, ..)) => a,
568
			(4, Junctions::X5(_, _, _, _, ref mut a)) => a,
569
			(4, Junctions::X6(_, _, _, _, ref mut a, ..)) => a,
570
			(4, Junctions::X7(_, _, _, _, ref mut a, ..)) => a,
571
			(4, Junctions::X8(_, _, _, _, ref mut a, ..)) => a,
572
			(5, Junctions::X6(_, _, _, _, _, ref mut a)) => a,
573
			(5, Junctions::X7(_, _, _, _, _, ref mut a, ..)) => a,
574
			(5, Junctions::X8(_, _, _, _, _, ref mut a, ..)) => a,
575
			(6, Junctions::X7(_, _, _, _, _, _, ref mut a)) => a,
576
			(6, Junctions::X8(_, _, _, _, _, _, ref mut a, ..)) => a,
577
			(7, Junctions::X8(_, _, _, _, _, _, _, ref mut a)) => a,
578
			_ => return None,
579
		})
580
	}
581

            
582
	/// Returns a reference iterator over the junctions.
583
	pub fn iter(&self) -> JunctionsRefIterator {
584
		JunctionsRefIterator { junctions: self, next: 0, back: 0 }
585
	}
586

            
587
	/// Ensures that self begins with `prefix` and that it has a single `Junction` item following.
588
	/// If so, returns a reference to this `Junction` item.
589
	///
590
	/// # Example
591
	/// ```rust
592
	/// # use staging_xcm::v3::{Junctions::*, Junction::*};
593
	/// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild);
594
	/// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild));
595
	/// assert_eq!(m.match_and_split(&X1(Parachain(2))), None);
596
	/// ```
597
	pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> {
598
		if prefix.len() + 1 != self.len() {
599
			return None
600
		}
601
		for i in 0..prefix.len() {
602
			if prefix.at(i) != self.at(i) {
603
				return None
604
			}
605
		}
606
		return self.at(prefix.len())
607
	}
608

            
609
	pub fn starts_with(&self, prefix: &Junctions) -> bool {
610
		prefix.len() <= self.len() && prefix.iter().zip(self.iter()).all(|(x, y)| x == y)
611
	}
612
}
613

            
614
impl TryFrom<MultiLocation> for Junctions {
615
	type Error = MultiLocation;
616
	fn try_from(x: MultiLocation) -> result::Result<Self, MultiLocation> {
617
		if x.parents > 0 {
618
			Err(x)
619
		} else {
620
			Ok(x.interior)
621
		}
622
	}
623
}
624

            
625
impl<T: Into<Junction>> From<T> for Junctions {
626
	fn from(x: T) -> Self {
627
		Self::X1(x.into())
628
	}
629
}
630

            
631
impl From<[Junction; 0]> for Junctions {
632
	fn from(_: [Junction; 0]) -> Self {
633
		Self::Here
634
	}
635
}
636

            
637
impl From<()> for Junctions {
638
	fn from(_: ()) -> Self {
639
		Self::Here
640
	}
641
}
642

            
643
10992
xcm_procedural::impl_conversion_functions_for_junctions_v3!();
644

            
645
#[cfg(test)]
646
mod tests {
647
	use super::{super::prelude::*, *};
648

            
649
	#[test]
650
	fn inverting_works() {
651
		let context: InteriorMultiLocation = (Parachain(1000), PalletInstance(42)).into();
652
		let target = (Parent, PalletInstance(69)).into();
653
		let expected = (Parent, PalletInstance(42)).into();
654
		let inverted = context.invert_target(&target).unwrap();
655
		assert_eq!(inverted, expected);
656

            
657
		let context: InteriorMultiLocation =
658
			(Parachain(1000), PalletInstance(42), GeneralIndex(1)).into();
659
		let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into();
660
		let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into();
661
		let inverted = context.invert_target(&target).unwrap();
662
		assert_eq!(inverted, expected);
663
	}
664

            
665
	#[test]
666
	fn relative_to_works() {
667
		use Junctions::*;
668
		use NetworkId::*;
669
		assert_eq!(X1(Polkadot.into()).relative_to(&X1(Kusama.into())), (Parent, Polkadot).into());
670
		let base = X3(Kusama.into(), Parachain(1), PalletInstance(1));
671

            
672
		// Ancestors.
673
		assert_eq!(Here.relative_to(&base), (Parent, Parent, Parent).into());
674
		assert_eq!(X1(Kusama.into()).relative_to(&base), (Parent, Parent).into());
675
		assert_eq!(X2(Kusama.into(), Parachain(1)).relative_to(&base), (Parent,).into());
676
		assert_eq!(
677
			X3(Kusama.into(), Parachain(1), PalletInstance(1)).relative_to(&base),
678
			Here.into()
679
		);
680

            
681
		// Ancestors with one child.
682
		assert_eq!(
683
			X1(Polkadot.into()).relative_to(&base),
684
			(Parent, Parent, Parent, Polkadot).into()
685
		);
686
		assert_eq!(
687
			X2(Kusama.into(), Parachain(2)).relative_to(&base),
688
			(Parent, Parent, Parachain(2)).into()
689
		);
690
		assert_eq!(
691
			X3(Kusama.into(), Parachain(1), PalletInstance(2)).relative_to(&base),
692
			(Parent, PalletInstance(2)).into()
693
		);
694
		assert_eq!(
695
			X4(Kusama.into(), Parachain(1), PalletInstance(1), [1u8; 32].into()).relative_to(&base),
696
			([1u8; 32],).into()
697
		);
698

            
699
		// Ancestors with grandchildren.
700
		assert_eq!(
701
			X2(Polkadot.into(), Parachain(1)).relative_to(&base),
702
			(Parent, Parent, Parent, Polkadot, Parachain(1)).into()
703
		);
704
		assert_eq!(
705
			X3(Kusama.into(), Parachain(2), PalletInstance(1)).relative_to(&base),
706
			(Parent, Parent, Parachain(2), PalletInstance(1)).into()
707
		);
708
		assert_eq!(
709
			X4(Kusama.into(), Parachain(1), PalletInstance(2), [1u8; 32].into()).relative_to(&base),
710
			(Parent, PalletInstance(2), [1u8; 32]).into()
711
		);
712
		assert_eq!(
713
			X5(Kusama.into(), Parachain(1), PalletInstance(1), [1u8; 32].into(), 1u128.into())
714
				.relative_to(&base),
715
			([1u8; 32], 1u128).into()
716
		);
717
	}
718

            
719
	#[test]
720
	fn global_consensus_works() {
721
		use Junctions::*;
722
		use NetworkId::*;
723
		assert_eq!(X1(Polkadot.into()).global_consensus(), Ok(Polkadot));
724
		assert_eq!(X2(Kusama.into(), 1u64.into()).global_consensus(), Ok(Kusama));
725
		assert_eq!(Here.global_consensus(), Err(()));
726
		assert_eq!(X1(1u64.into()).global_consensus(), Err(()));
727
		assert_eq!(X2(1u64.into(), Kusama.into()).global_consensus(), Err(()));
728
	}
729

            
730
	#[test]
731
	fn test_conversion() {
732
		use super::{Junction::*, Junctions::*, NetworkId::*};
733
		let x: Junctions = GlobalConsensus(Polkadot).into();
734
		assert_eq!(x, X1(GlobalConsensus(Polkadot)));
735
		let x: Junctions = Polkadot.into();
736
		assert_eq!(x, X1(GlobalConsensus(Polkadot)));
737
		let x: Junctions = (Polkadot, Kusama).into();
738
		assert_eq!(x, X2(GlobalConsensus(Polkadot), GlobalConsensus(Kusama)));
739
	}
740
}