referrerpolicy=no-referrer-when-downgrade

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, DecodeWithMemTracking, 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	DecodeWithMemTracking,
42	Debug,
43	TypeInfo,
44	MaxEncodedLen,
45	serde::Serialize,
46	serde::Deserialize,
47)]
48#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
49#[scale_info(replace_segment("staging_xcm", "xcm"))]
50pub enum Junctions {
51	/// The interpreting consensus system.
52	Here,
53	/// A relative path comprising 1 junction.
54	X1(Junction),
55	/// A relative path comprising 2 junctions.
56	X2(Junction, Junction),
57	/// A relative path comprising 3 junctions.
58	X3(Junction, Junction, Junction),
59	/// A relative path comprising 4 junctions.
60	X4(Junction, Junction, Junction, Junction),
61	/// A relative path comprising 5 junctions.
62	X5(Junction, Junction, Junction, Junction, Junction),
63	/// A relative path comprising 6 junctions.
64	X6(Junction, Junction, Junction, Junction, Junction, Junction),
65	/// A relative path comprising 7 junctions.
66	X7(Junction, Junction, Junction, Junction, Junction, Junction, Junction),
67	/// A relative path comprising 8 junctions.
68	X8(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction),
69}
70
71macro_rules! impl_junction {
72	($count:expr, $variant:ident, ($($index:literal),+)) => {
73		/// Additional helper for building junctions
74		/// Useful for converting to future XCM versions
75		impl From<[Junction; $count]> for Junctions {
76			fn from(junctions: [Junction; $count]) -> Self {
77				Self::$variant($(junctions[$index]),*)
78			}
79		}
80	};
81}
82
83impl_junction!(1, X1, (0));
84impl_junction!(2, X2, (0, 1));
85impl_junction!(3, X3, (0, 1, 2));
86impl_junction!(4, X4, (0, 1, 2, 3));
87impl_junction!(5, X5, (0, 1, 2, 3, 4));
88impl_junction!(6, X6, (0, 1, 2, 3, 4, 5));
89impl_junction!(7, X7, (0, 1, 2, 3, 4, 5, 6));
90impl_junction!(8, X8, (0, 1, 2, 3, 4, 5, 6, 7));
91
92pub struct JunctionsIterator(Junctions);
93impl Iterator for JunctionsIterator {
94	type Item = Junction;
95	fn next(&mut self) -> Option<Junction> {
96		self.0.take_first()
97	}
98}
99
100impl DoubleEndedIterator for JunctionsIterator {
101	fn next_back(&mut self) -> Option<Junction> {
102		self.0.take_last()
103	}
104}
105
106pub struct JunctionsRefIterator<'a> {
107	junctions: &'a Junctions,
108	next: usize,
109	back: usize,
110}
111
112impl<'a> Iterator for JunctionsRefIterator<'a> {
113	type Item = &'a Junction;
114	fn next(&mut self) -> Option<&'a Junction> {
115		if self.next.saturating_add(self.back) >= self.junctions.len() {
116			return None
117		}
118
119		let result = self.junctions.at(self.next);
120		self.next += 1;
121		result
122	}
123}
124
125impl<'a> DoubleEndedIterator for JunctionsRefIterator<'a> {
126	fn next_back(&mut self) -> Option<&'a Junction> {
127		let next_back = self.back.saturating_add(1);
128		// checked_sub here, because if the result is less than 0, we end iteration
129		let index = self.junctions.len().checked_sub(next_back)?;
130		if self.next > index {
131			return None
132		}
133		self.back = next_back;
134
135		self.junctions.at(index)
136	}
137}
138impl<'a> IntoIterator for &'a Junctions {
139	type Item = &'a Junction;
140	type IntoIter = JunctionsRefIterator<'a>;
141	fn into_iter(self) -> Self::IntoIter {
142		JunctionsRefIterator { junctions: self, next: 0, back: 0 }
143	}
144}
145
146impl IntoIterator for Junctions {
147	type Item = Junction;
148	type IntoIter = JunctionsIterator;
149	fn into_iter(self) -> Self::IntoIter {
150		JunctionsIterator(self)
151	}
152}
153
154impl Junctions {
155	/// Convert `self` into a `MultiLocation` containing 0 parents.
156	///
157	/// Similar to `Into::into`, except that this method can be used in a const evaluation context.
158	pub const fn into_location(self) -> MultiLocation {
159		MultiLocation { parents: 0, interior: self }
160	}
161
162	/// Convert `self` into a `MultiLocation` containing `n` parents.
163	///
164	/// Similar to `Self::into_location`, with the added ability to specify the number of parent
165	/// junctions.
166	pub const fn into_exterior(self, n: u8) -> MultiLocation {
167		MultiLocation { parents: n, interior: self }
168	}
169
170	/// Remove the `NetworkId` value in any `Junction`s.
171	pub fn remove_network_id(&mut self) {
172		self.for_each_mut(Junction::remove_network_id);
173	}
174
175	/// Treating `self` as the universal context, return the location of the local consensus system
176	/// from the point of view of the given `target`.
177	pub fn invert_target(mut self, target: &MultiLocation) -> Result<MultiLocation, ()> {
178		let mut junctions = Self::Here;
179		for _ in 0..target.parent_count() {
180			junctions = junctions
181				.pushed_front_with(self.take_last().unwrap_or(Junction::OnlyChild))
182				.map_err(|_| ())?;
183		}
184		let parents = target.interior().len() as u8;
185		Ok(MultiLocation::new(parents, junctions))
186	}
187
188	/// Execute a function `f` on every junction. We use this since we cannot implement a mutable
189	/// `Iterator` without unsafe code.
190	pub fn for_each_mut(&mut self, mut x: impl FnMut(&mut Junction)) {
191		match self {
192			Junctions::Here => {},
193			Junctions::X1(a) => {
194				x(a);
195			},
196			Junctions::X2(a, b) => {
197				x(a);
198				x(b);
199			},
200			Junctions::X3(a, b, c) => {
201				x(a);
202				x(b);
203				x(c);
204			},
205			Junctions::X4(a, b, c, d) => {
206				x(a);
207				x(b);
208				x(c);
209				x(d);
210			},
211			Junctions::X5(a, b, c, d, e) => {
212				x(a);
213				x(b);
214				x(c);
215				x(d);
216				x(e);
217			},
218			Junctions::X6(a, b, c, d, e, f) => {
219				x(a);
220				x(b);
221				x(c);
222				x(d);
223				x(e);
224				x(f);
225			},
226			Junctions::X7(a, b, c, d, e, f, g) => {
227				x(a);
228				x(b);
229				x(c);
230				x(d);
231				x(e);
232				x(f);
233				x(g);
234			},
235			Junctions::X8(a, b, c, d, e, f, g, h) => {
236				x(a);
237				x(b);
238				x(c);
239				x(d);
240				x(e);
241				x(f);
242				x(g);
243				x(h);
244			},
245		}
246	}
247
248	/// Extract the network ID treating this value as a universal location.
249	///
250	/// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate
251	/// that this value is not a universal location.
252	pub fn global_consensus(&self) -> Result<NetworkId, ()> {
253		if let Some(Junction::GlobalConsensus(network)) = self.first() {
254			Ok(*network)
255		} else {
256			Err(())
257		}
258	}
259
260	/// Extract the network ID and the interior consensus location, treating this value as a
261	/// universal location.
262	///
263	/// This will return an `Err` if the first item is not a `GlobalConsensus`, which would indicate
264	/// that this value is not a universal location.
265	pub fn split_global(self) -> Result<(NetworkId, Junctions), ()> {
266		match self.split_first() {
267			(location, Some(Junction::GlobalConsensus(network))) => Ok((network, location)),
268			_ => return Err(()),
269		}
270	}
271
272	/// Treat `self` as a universal location and the context of `relative`, returning the universal
273	/// location of relative.
274	///
275	/// This will return an error if `relative` has as many (or more) parents than there are
276	/// junctions in `self`, implying that relative refers into a different global consensus.
277	pub fn within_global(mut self, relative: MultiLocation) -> Result<Self, ()> {
278		if self.len() <= relative.parents as usize {
279			return Err(())
280		}
281		for _ in 0..relative.parents {
282			self.take_last();
283		}
284		for j in relative.interior {
285			self.push(j).map_err(|_| ())?;
286		}
287		Ok(self)
288	}
289
290	/// Consumes `self` and returns how `viewer` would address it locally.
291	pub fn relative_to(mut self, viewer: &Junctions) -> MultiLocation {
292		let mut i = 0;
293		while match (self.first(), viewer.at(i)) {
294			(Some(x), Some(y)) => x == y,
295			_ => false,
296		} {
297			self = self.split_first().0;
298			// NOTE: Cannot overflow as loop can only iterate at most `MAX_JUNCTIONS` times.
299			i += 1;
300		}
301		// AUDIT NOTES:
302		// - above loop ensures that `i <= viewer.len()`.
303		// - `viewer.len()` is at most `MAX_JUNCTIONS`, so won't overflow a `u8`.
304		MultiLocation { parents: (viewer.len() - i) as u8, interior: self }
305	}
306
307	/// Returns first junction, or `None` if the location is empty.
308	pub fn first(&self) -> Option<&Junction> {
309		match &self {
310			Junctions::Here => None,
311			Junctions::X1(ref a) => Some(a),
312			Junctions::X2(ref a, ..) => Some(a),
313			Junctions::X3(ref a, ..) => Some(a),
314			Junctions::X4(ref a, ..) => Some(a),
315			Junctions::X5(ref a, ..) => Some(a),
316			Junctions::X6(ref a, ..) => Some(a),
317			Junctions::X7(ref a, ..) => Some(a),
318			Junctions::X8(ref a, ..) => Some(a),
319		}
320	}
321
322	/// Returns last junction, or `None` if the location is empty.
323	pub fn last(&self) -> Option<&Junction> {
324		match &self {
325			Junctions::Here => None,
326			Junctions::X1(ref a) => Some(a),
327			Junctions::X2(.., ref a) => Some(a),
328			Junctions::X3(.., ref a) => Some(a),
329			Junctions::X4(.., ref a) => Some(a),
330			Junctions::X5(.., ref a) => Some(a),
331			Junctions::X6(.., ref a) => Some(a),
332			Junctions::X7(.., ref a) => Some(a),
333			Junctions::X8(.., ref a) => Some(a),
334		}
335	}
336
337	/// Splits off the first junction, returning the remaining suffix (first item in tuple) and the
338	/// first element (second item in tuple) or `None` if it was empty.
339	pub fn split_first(self) -> (Junctions, Option<Junction>) {
340		match self {
341			Junctions::Here => (Junctions::Here, None),
342			Junctions::X1(a) => (Junctions::Here, Some(a)),
343			Junctions::X2(a, b) => (Junctions::X1(b), Some(a)),
344			Junctions::X3(a, b, c) => (Junctions::X2(b, c), Some(a)),
345			Junctions::X4(a, b, c, d) => (Junctions::X3(b, c, d), Some(a)),
346			Junctions::X5(a, b, c, d, e) => (Junctions::X4(b, c, d, e), Some(a)),
347			Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(b, c, d, e, f), Some(a)),
348			Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(b, c, d, e, f, g), Some(a)),
349			Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(b, c, d, e, f, g, h), Some(a)),
350		}
351	}
352
353	/// Splits off the last junction, returning the remaining prefix (first item in tuple) and the
354	/// last element (second item in tuple) or `None` if it was empty.
355	pub fn split_last(self) -> (Junctions, Option<Junction>) {
356		match self {
357			Junctions::Here => (Junctions::Here, None),
358			Junctions::X1(a) => (Junctions::Here, Some(a)),
359			Junctions::X2(a, b) => (Junctions::X1(a), Some(b)),
360			Junctions::X3(a, b, c) => (Junctions::X2(a, b), Some(c)),
361			Junctions::X4(a, b, c, d) => (Junctions::X3(a, b, c), Some(d)),
362			Junctions::X5(a, b, c, d, e) => (Junctions::X4(a, b, c, d), Some(e)),
363			Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(a, b, c, d, e), Some(f)),
364			Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(a, b, c, d, e, f), Some(g)),
365			Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(a, b, c, d, e, f, g), Some(h)),
366		}
367	}
368
369	/// Removes the first element from `self`, returning it (or `None` if it was empty).
370	pub fn take_first(&mut self) -> Option<Junction> {
371		let mut d = Junctions::Here;
372		mem::swap(&mut *self, &mut d);
373		let (tail, head) = d.split_first();
374		*self = tail;
375		head
376	}
377
378	/// Removes the last element from `self`, returning it (or `None` if it was empty).
379	pub fn take_last(&mut self) -> Option<Junction> {
380		let mut d = Junctions::Here;
381		mem::swap(&mut *self, &mut d);
382		let (head, tail) = d.split_last();
383		*self = head;
384		tail
385	}
386
387	/// Mutates `self` to be appended with `new` or returns an `Err` with `new` if would overflow.
388	pub fn push(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
389		let new = new.into();
390		let mut dummy = Junctions::Here;
391		mem::swap(self, &mut dummy);
392		match dummy.pushed_with(new) {
393			Ok(s) => {
394				*self = s;
395				Ok(())
396			},
397			Err((s, j)) => {
398				*self = s;
399				Err(j)
400			},
401		}
402	}
403
404	/// Mutates `self` to be prepended with `new` or returns an `Err` with `new` if would overflow.
405	pub fn push_front(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
406		let new = new.into();
407		let mut dummy = Junctions::Here;
408		mem::swap(self, &mut dummy);
409		match dummy.pushed_front_with(new) {
410			Ok(s) => {
411				*self = s;
412				Ok(())
413			},
414			Err((s, j)) => {
415				*self = s;
416				Err(j)
417			},
418		}
419	}
420
421	/// Consumes `self` and returns a `Junctions` suffixed with `new`, or an `Err` with the
422	/// original value of `self` and `new` in case of overflow.
423	pub fn pushed_with(self, new: impl Into<Junction>) -> result::Result<Self, (Self, Junction)> {
424		let new = new.into();
425		Ok(match self {
426			Junctions::Here => Junctions::X1(new),
427			Junctions::X1(a) => Junctions::X2(a, new),
428			Junctions::X2(a, b) => Junctions::X3(a, b, new),
429			Junctions::X3(a, b, c) => Junctions::X4(a, b, c, new),
430			Junctions::X4(a, b, c, d) => Junctions::X5(a, b, c, d, new),
431			Junctions::X5(a, b, c, d, e) => Junctions::X6(a, b, c, d, e, new),
432			Junctions::X6(a, b, c, d, e, f) => Junctions::X7(a, b, c, d, e, f, new),
433			Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(a, b, c, d, e, f, g, new),
434			s => Err((s, new))?,
435		})
436	}
437
438	/// Consumes `self` and returns a `Junctions` prefixed with `new`, or an `Err` with the
439	/// original value of `self` and `new` in case of overflow.
440	pub fn pushed_front_with(
441		self,
442		new: impl Into<Junction>,
443	) -> result::Result<Self, (Self, Junction)> {
444		let new = new.into();
445		Ok(match self {
446			Junctions::Here => Junctions::X1(new),
447			Junctions::X1(a) => Junctions::X2(new, a),
448			Junctions::X2(a, b) => Junctions::X3(new, a, b),
449			Junctions::X3(a, b, c) => Junctions::X4(new, a, b, c),
450			Junctions::X4(a, b, c, d) => Junctions::X5(new, a, b, c, d),
451			Junctions::X5(a, b, c, d, e) => Junctions::X6(new, a, b, c, d, e),
452			Junctions::X6(a, b, c, d, e, f) => Junctions::X7(new, a, b, c, d, e, f),
453			Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(new, a, b, c, d, e, f, g),
454			s => Err((s, new))?,
455		})
456	}
457
458	/// Mutate `self` so that it is suffixed with `suffix`.
459	///
460	/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
461	///
462	/// # Example
463	/// ```rust
464	/// # use staging_xcm::v3::{Junctions::*, Junction::*, MultiLocation};
465	/// let mut m = X1(Parachain(21));
466	/// assert_eq!(m.append_with(X1(PalletInstance(3))), Ok(()));
467	/// assert_eq!(m, X2(Parachain(21), PalletInstance(3)));
468	/// ```
469	pub fn append_with(&mut self, suffix: impl Into<Junctions>) -> Result<(), Junctions> {
470		let suffix = suffix.into();
471		if self.len().saturating_add(suffix.len()) > MAX_JUNCTIONS {
472			return Err(suffix)
473		}
474		for j in suffix.into_iter() {
475			self.push(j).expect("Already checked the sum of the len()s; qed")
476		}
477		Ok(())
478	}
479
480	/// Returns the number of junctions in `self`.
481	pub const fn len(&self) -> usize {
482		match &self {
483			Junctions::Here => 0,
484			Junctions::X1(..) => 1,
485			Junctions::X2(..) => 2,
486			Junctions::X3(..) => 3,
487			Junctions::X4(..) => 4,
488			Junctions::X5(..) => 5,
489			Junctions::X6(..) => 6,
490			Junctions::X7(..) => 7,
491			Junctions::X8(..) => 8,
492		}
493	}
494
495	/// Returns the junction at index `i`, or `None` if the location doesn't contain that many
496	/// elements.
497	pub fn at(&self, i: usize) -> Option<&Junction> {
498		Some(match (i, self) {
499			(0, Junctions::X1(ref a)) => a,
500			(0, Junctions::X2(ref a, ..)) => a,
501			(0, Junctions::X3(ref a, ..)) => a,
502			(0, Junctions::X4(ref a, ..)) => a,
503			(0, Junctions::X5(ref a, ..)) => a,
504			(0, Junctions::X6(ref a, ..)) => a,
505			(0, Junctions::X7(ref a, ..)) => a,
506			(0, Junctions::X8(ref a, ..)) => a,
507			(1, Junctions::X2(_, ref a)) => a,
508			(1, Junctions::X3(_, ref a, ..)) => a,
509			(1, Junctions::X4(_, ref a, ..)) => a,
510			(1, Junctions::X5(_, ref a, ..)) => a,
511			(1, Junctions::X6(_, ref a, ..)) => a,
512			(1, Junctions::X7(_, ref a, ..)) => a,
513			(1, Junctions::X8(_, ref a, ..)) => a,
514			(2, Junctions::X3(_, _, ref a)) => a,
515			(2, Junctions::X4(_, _, ref a, ..)) => a,
516			(2, Junctions::X5(_, _, ref a, ..)) => a,
517			(2, Junctions::X6(_, _, ref a, ..)) => a,
518			(2, Junctions::X7(_, _, ref a, ..)) => a,
519			(2, Junctions::X8(_, _, ref a, ..)) => a,
520			(3, Junctions::X4(_, _, _, ref a)) => a,
521			(3, Junctions::X5(_, _, _, ref a, ..)) => a,
522			(3, Junctions::X6(_, _, _, ref a, ..)) => a,
523			(3, Junctions::X7(_, _, _, ref a, ..)) => a,
524			(3, Junctions::X8(_, _, _, ref a, ..)) => a,
525			(4, Junctions::X5(_, _, _, _, ref a)) => a,
526			(4, Junctions::X6(_, _, _, _, ref a, ..)) => a,
527			(4, Junctions::X7(_, _, _, _, ref a, ..)) => a,
528			(4, Junctions::X8(_, _, _, _, ref a, ..)) => a,
529			(5, Junctions::X6(_, _, _, _, _, ref a)) => a,
530			(5, Junctions::X7(_, _, _, _, _, ref a, ..)) => a,
531			(5, Junctions::X8(_, _, _, _, _, ref a, ..)) => a,
532			(6, Junctions::X7(_, _, _, _, _, _, ref a)) => a,
533			(6, Junctions::X8(_, _, _, _, _, _, ref a, ..)) => a,
534			(7, Junctions::X8(_, _, _, _, _, _, _, ref a)) => a,
535			_ => return None,
536		})
537	}
538
539	/// Returns a mutable reference to the junction at index `i`, or `None` if the location doesn't
540	/// contain that many elements.
541	pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
542		Some(match (i, self) {
543			(0, Junctions::X1(ref mut a)) => a,
544			(0, Junctions::X2(ref mut a, ..)) => a,
545			(0, Junctions::X3(ref mut a, ..)) => a,
546			(0, Junctions::X4(ref mut a, ..)) => a,
547			(0, Junctions::X5(ref mut a, ..)) => a,
548			(0, Junctions::X6(ref mut a, ..)) => a,
549			(0, Junctions::X7(ref mut a, ..)) => a,
550			(0, Junctions::X8(ref mut a, ..)) => a,
551			(1, Junctions::X2(_, ref mut a)) => a,
552			(1, Junctions::X3(_, ref mut a, ..)) => a,
553			(1, Junctions::X4(_, ref mut a, ..)) => a,
554			(1, Junctions::X5(_, ref mut a, ..)) => a,
555			(1, Junctions::X6(_, ref mut a, ..)) => a,
556			(1, Junctions::X7(_, ref mut a, ..)) => a,
557			(1, Junctions::X8(_, ref mut a, ..)) => a,
558			(2, Junctions::X3(_, _, ref mut a)) => a,
559			(2, Junctions::X4(_, _, ref mut a, ..)) => a,
560			(2, Junctions::X5(_, _, ref mut a, ..)) => a,
561			(2, Junctions::X6(_, _, ref mut a, ..)) => a,
562			(2, Junctions::X7(_, _, ref mut a, ..)) => a,
563			(2, Junctions::X8(_, _, ref mut a, ..)) => a,
564			(3, Junctions::X4(_, _, _, ref mut a)) => a,
565			(3, Junctions::X5(_, _, _, ref mut a, ..)) => a,
566			(3, Junctions::X6(_, _, _, ref mut a, ..)) => a,
567			(3, Junctions::X7(_, _, _, ref mut a, ..)) => a,
568			(3, Junctions::X8(_, _, _, ref mut a, ..)) => a,
569			(4, Junctions::X5(_, _, _, _, ref mut a)) => a,
570			(4, Junctions::X6(_, _, _, _, ref mut a, ..)) => a,
571			(4, Junctions::X7(_, _, _, _, ref mut a, ..)) => a,
572			(4, Junctions::X8(_, _, _, _, ref mut a, ..)) => a,
573			(5, Junctions::X6(_, _, _, _, _, ref mut a)) => a,
574			(5, Junctions::X7(_, _, _, _, _, ref mut a, ..)) => a,
575			(5, Junctions::X8(_, _, _, _, _, ref mut a, ..)) => a,
576			(6, Junctions::X7(_, _, _, _, _, _, ref mut a)) => a,
577			(6, Junctions::X8(_, _, _, _, _, _, ref mut a, ..)) => a,
578			(7, Junctions::X8(_, _, _, _, _, _, _, ref mut a)) => a,
579			_ => return None,
580		})
581	}
582
583	/// Returns a reference iterator over the junctions.
584	pub fn iter(&self) -> JunctionsRefIterator {
585		JunctionsRefIterator { junctions: self, next: 0, back: 0 }
586	}
587
588	/// Ensures that self begins with `prefix` and that it has a single `Junction` item following.
589	/// If so, returns a reference to this `Junction` item.
590	///
591	/// # Example
592	/// ```rust
593	/// # use staging_xcm::v3::{Junctions::*, Junction::*};
594	/// let mut m = X3(Parachain(2), PalletInstance(3), OnlyChild);
595	/// assert_eq!(m.match_and_split(&X2(Parachain(2), PalletInstance(3))), Some(&OnlyChild));
596	/// assert_eq!(m.match_and_split(&X1(Parachain(2))), None);
597	/// ```
598	pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> {
599		if prefix.len() + 1 != self.len() {
600			return None
601		}
602		for i in 0..prefix.len() {
603			if prefix.at(i) != self.at(i) {
604				return None
605			}
606		}
607		return self.at(prefix.len())
608	}
609
610	pub fn starts_with(&self, prefix: &Junctions) -> bool {
611		prefix.len() <= self.len() && prefix.iter().zip(self.iter()).all(|(x, y)| x == y)
612	}
613}
614
615impl TryFrom<MultiLocation> for Junctions {
616	type Error = MultiLocation;
617	fn try_from(x: MultiLocation) -> result::Result<Self, MultiLocation> {
618		if x.parents > 0 {
619			Err(x)
620		} else {
621			Ok(x.interior)
622		}
623	}
624}
625
626impl<T: Into<Junction>> From<T> for Junctions {
627	fn from(x: T) -> Self {
628		Self::X1(x.into())
629	}
630}
631
632impl From<[Junction; 0]> for Junctions {
633	fn from(_: [Junction; 0]) -> Self {
634		Self::Here
635	}
636}
637
638impl From<()> for Junctions {
639	fn from(_: ()) -> Self {
640		Self::Here
641	}
642}
643
644xcm_procedural::impl_conversion_functions_for_junctions_v3!();
645
646#[cfg(test)]
647mod tests {
648	use super::{super::prelude::*, *};
649
650	#[test]
651	fn inverting_works() {
652		let context: InteriorMultiLocation = (Parachain(1000), PalletInstance(42)).into();
653		let target = (Parent, PalletInstance(69)).into();
654		let expected = (Parent, PalletInstance(42)).into();
655		let inverted = context.invert_target(&target).unwrap();
656		assert_eq!(inverted, expected);
657
658		let context: InteriorMultiLocation =
659			(Parachain(1000), PalletInstance(42), GeneralIndex(1)).into();
660		let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into();
661		let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into();
662		let inverted = context.invert_target(&target).unwrap();
663		assert_eq!(inverted, expected);
664	}
665
666	#[test]
667	fn relative_to_works() {
668		use Junctions::*;
669		use NetworkId::*;
670		assert_eq!(X1(Polkadot.into()).relative_to(&X1(Kusama.into())), (Parent, Polkadot).into());
671		let base = X3(Kusama.into(), Parachain(1), PalletInstance(1));
672
673		// Ancestors.
674		assert_eq!(Here.relative_to(&base), (Parent, Parent, Parent).into());
675		assert_eq!(X1(Kusama.into()).relative_to(&base), (Parent, Parent).into());
676		assert_eq!(X2(Kusama.into(), Parachain(1)).relative_to(&base), (Parent,).into());
677		assert_eq!(
678			X3(Kusama.into(), Parachain(1), PalletInstance(1)).relative_to(&base),
679			Here.into()
680		);
681
682		// Ancestors with one child.
683		assert_eq!(
684			X1(Polkadot.into()).relative_to(&base),
685			(Parent, Parent, Parent, Polkadot).into()
686		);
687		assert_eq!(
688			X2(Kusama.into(), Parachain(2)).relative_to(&base),
689			(Parent, Parent, Parachain(2)).into()
690		);
691		assert_eq!(
692			X3(Kusama.into(), Parachain(1), PalletInstance(2)).relative_to(&base),
693			(Parent, PalletInstance(2)).into()
694		);
695		assert_eq!(
696			X4(Kusama.into(), Parachain(1), PalletInstance(1), [1u8; 32].into()).relative_to(&base),
697			([1u8; 32],).into()
698		);
699
700		// Ancestors with grandchildren.
701		assert_eq!(
702			X2(Polkadot.into(), Parachain(1)).relative_to(&base),
703			(Parent, Parent, Parent, Polkadot, Parachain(1)).into()
704		);
705		assert_eq!(
706			X3(Kusama.into(), Parachain(2), PalletInstance(1)).relative_to(&base),
707			(Parent, Parent, Parachain(2), PalletInstance(1)).into()
708		);
709		assert_eq!(
710			X4(Kusama.into(), Parachain(1), PalletInstance(2), [1u8; 32].into()).relative_to(&base),
711			(Parent, PalletInstance(2), [1u8; 32]).into()
712		);
713		assert_eq!(
714			X5(Kusama.into(), Parachain(1), PalletInstance(1), [1u8; 32].into(), 1u128.into())
715				.relative_to(&base),
716			([1u8; 32], 1u128).into()
717		);
718	}
719
720	#[test]
721	fn global_consensus_works() {
722		use Junctions::*;
723		use NetworkId::*;
724		assert_eq!(X1(Polkadot.into()).global_consensus(), Ok(Polkadot));
725		assert_eq!(X2(Kusama.into(), 1u64.into()).global_consensus(), Ok(Kusama));
726		assert_eq!(Here.global_consensus(), Err(()));
727		assert_eq!(X1(1u64.into()).global_consensus(), Err(()));
728		assert_eq!(X2(1u64.into(), Kusama.into()).global_consensus(), Err(()));
729	}
730
731	#[test]
732	fn test_conversion() {
733		use super::{Junction::*, Junctions::*, NetworkId::*};
734		let x: Junctions = GlobalConsensus(Polkadot).into();
735		assert_eq!(x, X1(GlobalConsensus(Polkadot)));
736		let x: Junctions = Polkadot.into();
737		assert_eq!(x, X1(GlobalConsensus(Polkadot)));
738		let x: Junctions = (Polkadot, Kusama).into();
739		assert_eq!(x, X2(GlobalConsensus(Polkadot), GlobalConsensus(Kusama)));
740	}
741}