staging_xcm/v3/
junctions.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
17//! XCM `Junctions`/`InteriorMultiLocation` datatype.
18
19use super::{Junction, MultiLocation, NetworkId};
20use codec::{Decode, Encode, MaxEncodedLen};
21use core::{mem, result};
22use scale_info::TypeInfo;
23
24/// Maximum number of `Junction`s that a `Junctions` can contain.
25pub(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	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"))]
49pub enum Junctions {
50	/// The interpreting consensus system.
51	Here,
52	/// A relative path comprising 1 junction.
53	X1(Junction),
54	/// A relative path comprising 2 junctions.
55	X2(Junction, Junction),
56	/// A relative path comprising 3 junctions.
57	X3(Junction, Junction, Junction),
58	/// A relative path comprising 4 junctions.
59	X4(Junction, Junction, Junction, Junction),
60	/// A relative path comprising 5 junctions.
61	X5(Junction, Junction, Junction, Junction, Junction),
62	/// A relative path comprising 6 junctions.
63	X6(Junction, Junction, Junction, Junction, Junction, Junction),
64	/// A relative path comprising 7 junctions.
65	X7(Junction, Junction, Junction, Junction, Junction, Junction, Junction),
66	/// A relative path comprising 8 junctions.
67	X8(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction),
68}
69
70macro_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
82impl_junction!(1, X1, (0));
83impl_junction!(2, X2, (0, 1));
84impl_junction!(3, X3, (0, 1, 2));
85impl_junction!(4, X4, (0, 1, 2, 3));
86impl_junction!(5, X5, (0, 1, 2, 3, 4));
87impl_junction!(6, X6, (0, 1, 2, 3, 4, 5));
88impl_junction!(7, X7, (0, 1, 2, 3, 4, 5, 6));
89impl_junction!(8, X8, (0, 1, 2, 3, 4, 5, 6, 7));
90
91pub struct JunctionsIterator(Junctions);
92impl Iterator for JunctionsIterator {
93	type Item = Junction;
94	fn next(&mut self) -> Option<Junction> {
95		self.0.take_first()
96	}
97}
98
99impl DoubleEndedIterator for JunctionsIterator {
100	fn next_back(&mut self) -> Option<Junction> {
101		self.0.take_last()
102	}
103}
104
105pub struct JunctionsRefIterator<'a> {
106	junctions: &'a Junctions,
107	next: usize,
108	back: usize,
109}
110
111impl<'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
124impl<'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}
137impl<'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
145impl IntoIterator for Junctions {
146	type Item = Junction;
147	type IntoIter = JunctionsIterator;
148	fn into_iter(self) -> Self::IntoIter {
149		JunctionsIterator(self)
150	}
151}
152
153impl 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
614impl 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
625impl<T: Into<Junction>> From<T> for Junctions {
626	fn from(x: T) -> Self {
627		Self::X1(x.into())
628	}
629}
630
631impl From<[Junction; 0]> for Junctions {
632	fn from(_: [Junction; 0]) -> Self {
633		Self::Here
634	}
635}
636
637impl From<()> for Junctions {
638	fn from(_: ()) -> Self {
639		Self::Here
640	}
641}
642
643xcm_procedural::impl_conversion_functions_for_junctions_v3!();
644
645#[cfg(test)]
646mod 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}