use super::Junction;
use crate::v3::MultiLocation as NewMultiLocation;
use core::{mem, result};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
#[derive(Clone, Decode, Encode, Eq, PartialEq, Ord, PartialOrd, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub struct MultiLocation {
pub parents: u8,
pub interior: Junctions,
}
impl Default for MultiLocation {
fn default() -> Self {
Self { parents: 0, interior: Junctions::Here }
}
}
pub type InteriorMultiLocation = Junctions;
impl MultiLocation {
pub fn new(parents: u8, junctions: Junctions) -> MultiLocation {
MultiLocation { parents, interior: junctions }
}
pub fn versioned(self) -> crate::VersionedMultiLocation {
self.into()
}
pub const fn here() -> MultiLocation {
MultiLocation { parents: 0, interior: Junctions::Here }
}
pub const fn parent() -> MultiLocation {
MultiLocation { parents: 1, interior: Junctions::Here }
}
pub const fn grandparent() -> MultiLocation {
MultiLocation { parents: 2, interior: Junctions::Here }
}
pub const fn ancestor(parents: u8) -> MultiLocation {
MultiLocation { parents, interior: Junctions::Here }
}
pub const fn is_here(&self) -> bool {
self.parents == 0 && self.interior.len() == 0
}
pub fn interior(&self) -> &Junctions {
&self.interior
}
pub fn interior_mut(&mut self) -> &mut Junctions {
&mut self.interior
}
pub const fn parent_count(&self) -> u8 {
self.parents
}
pub const fn contains_parents_only(&self, count: u8) -> bool {
matches!(self.interior, Junctions::Here) && self.parents == count
}
pub const fn len(&self) -> usize {
self.parent_count() as usize + self.interior.len()
}
pub fn first_interior(&self) -> Option<&Junction> {
self.interior.first()
}
pub fn last(&self) -> Option<&Junction> {
self.interior.last()
}
pub fn split_first_interior(self) -> (MultiLocation, Option<Junction>) {
let MultiLocation { parents, interior: junctions } = self;
let (suffix, first) = junctions.split_first();
let multilocation = MultiLocation { parents, interior: suffix };
(multilocation, first)
}
pub fn split_last_interior(self) -> (MultiLocation, Option<Junction>) {
let MultiLocation { parents, interior: junctions } = self;
let (prefix, last) = junctions.split_last();
let multilocation = MultiLocation { parents, interior: prefix };
(multilocation, last)
}
pub fn push_interior(&mut self, new: Junction) -> result::Result<(), Junction> {
self.interior.push(new)
}
pub fn push_front_interior(&mut self, new: Junction) -> result::Result<(), Junction> {
self.interior.push_front(new)
}
pub fn pushed_with_interior(self, new: Junction) -> result::Result<Self, (Self, Junction)> {
match self.interior.pushed_with(new) {
Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }),
Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)),
}
}
pub fn pushed_front_with_interior(
self,
new: Junction,
) -> result::Result<Self, (Self, Junction)> {
match self.interior.pushed_front_with(new) {
Ok(i) => Ok(MultiLocation { interior: i, parents: self.parents }),
Err((i, j)) => Err((MultiLocation { interior: i, parents: self.parents }, j)),
}
}
pub fn at(&self, i: usize) -> Option<&Junction> {
let num_parents = self.parents as usize;
if i < num_parents {
return None
}
self.interior.at(i - num_parents)
}
pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
let num_parents = self.parents as usize;
if i < num_parents {
return None
}
self.interior.at_mut(i - num_parents)
}
pub fn dec_parent(&mut self) {
self.parents = self.parents.saturating_sub(1);
}
pub fn take_first_interior(&mut self) -> Option<Junction> {
self.interior.take_first()
}
pub fn take_last(&mut self) -> Option<Junction> {
self.interior.take_last()
}
pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> {
if self.parents != prefix.parents {
return None
}
self.interior.match_and_split(&prefix.interior)
}
pub fn starts_with(&self, prefix: &MultiLocation) -> bool {
if self.parents != prefix.parents {
return false
}
self.interior.starts_with(&prefix.interior)
}
pub fn append_with(&mut self, suffix: Junctions) -> Result<(), Junctions> {
if self.interior.len().saturating_add(suffix.len()) > MAX_JUNCTIONS {
return Err(suffix)
}
for j in suffix.into_iter() {
self.interior.push(j).expect("Already checked the sum of the len()s; qed")
}
Ok(())
}
pub fn prepend_with(&mut self, mut prefix: MultiLocation) -> Result<(), MultiLocation> {
let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize);
let final_interior = self.interior.len().saturating_add(prepend_interior);
if final_interior > MAX_JUNCTIONS {
return Err(prefix)
}
let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len());
let final_parents = (prefix.parents as usize).saturating_add(suffix_parents);
if final_parents > 255 {
return Err(prefix)
}
while self.parents > 0 && prefix.take_last().is_some() {
self.dec_parent();
}
self.parents = self.parents.saturating_add(prefix.parents);
for j in prefix.interior.into_iter().rev() {
self.push_front_interior(j)
.expect("final_interior no greater than MAX_JUNCTIONS; qed");
}
Ok(())
}
pub fn reanchored(
mut self,
target: &MultiLocation,
ancestry: &MultiLocation,
) -> Result<Self, Self> {
match self.reanchor(target, ancestry) {
Ok(()) => Ok(self),
Err(()) => Err(self),
}
}
pub fn reanchor(&mut self, target: &MultiLocation, ancestry: &MultiLocation) -> Result<(), ()> {
let inverted_target = ancestry.inverted(target)?;
self.prepend_with(inverted_target).map_err(|_| ())?;
self.simplify(target.interior());
Ok(())
}
pub fn inverted(&self, target: &MultiLocation) -> Result<MultiLocation, ()> {
use Junction::OnlyChild;
let mut ancestry = self.clone();
let mut junctions = Junctions::Here;
for _ in 0..target.parent_count() {
junctions = junctions
.pushed_front_with(ancestry.interior.take_last().unwrap_or(OnlyChild))
.map_err(|_| ())?;
}
let parents = target.interior().len() as u8;
Ok(MultiLocation::new(parents, junctions))
}
pub fn simplify(&mut self, context: &Junctions) {
if context.len() < self.parents as usize {
return
}
while self.parents > 0 {
let maybe = context.at(context.len() - (self.parents as usize));
match (self.interior.first(), maybe) {
(Some(i), Some(j)) if i == j => {
self.interior.take_first();
self.parents -= 1;
},
_ => break,
}
}
}
}
impl TryFrom<NewMultiLocation> for MultiLocation {
type Error = ();
fn try_from(x: NewMultiLocation) -> result::Result<Self, ()> {
Ok(MultiLocation { parents: x.parents, interior: x.interior.try_into()? })
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Parent;
impl From<Parent> for MultiLocation {
fn from(_: Parent) -> Self {
MultiLocation { parents: 1, interior: Junctions::Here }
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct ParentThen(pub Junctions);
impl From<ParentThen> for MultiLocation {
fn from(ParentThen(interior): ParentThen) -> Self {
MultiLocation { parents: 1, interior }
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Ancestor(pub u8);
impl From<Ancestor> for MultiLocation {
fn from(Ancestor(parents): Ancestor) -> Self {
MultiLocation { parents, interior: Junctions::Here }
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct AncestorThen<Interior>(pub u8, pub Interior);
impl<Interior: Into<Junctions>> From<AncestorThen<Interior>> for MultiLocation {
fn from(AncestorThen(parents, interior): AncestorThen<Interior>) -> Self {
MultiLocation { parents, interior: interior.into() }
}
}
xcm_procedural::impl_conversion_functions_for_multilocation_v2!();
const MAX_JUNCTIONS: usize = 8;
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, TypeInfo, MaxEncodedLen)]
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
pub enum Junctions {
Here,
X1(Junction),
X2(Junction, Junction),
X3(Junction, Junction, Junction),
X4(Junction, Junction, Junction, Junction),
X5(Junction, Junction, Junction, Junction, Junction),
X6(Junction, Junction, Junction, Junction, Junction, Junction),
X7(Junction, Junction, Junction, Junction, Junction, Junction, Junction),
X8(Junction, Junction, Junction, Junction, Junction, Junction, Junction, Junction),
}
pub struct JunctionsIterator(Junctions);
impl Iterator for JunctionsIterator {
type Item = Junction;
fn next(&mut self) -> Option<Junction> {
self.0.take_first()
}
}
impl DoubleEndedIterator for JunctionsIterator {
fn next_back(&mut self) -> Option<Junction> {
self.0.take_last()
}
}
pub struct JunctionsRefIterator<'a> {
junctions: &'a Junctions,
next: usize,
back: usize,
}
impl<'a> Iterator for JunctionsRefIterator<'a> {
type Item = &'a Junction;
fn next(&mut self) -> Option<&'a Junction> {
if self.next.saturating_add(self.back) >= self.junctions.len() {
return None
}
let result = self.junctions.at(self.next);
self.next += 1;
result
}
}
impl<'a> DoubleEndedIterator for JunctionsRefIterator<'a> {
fn next_back(&mut self) -> Option<&'a Junction> {
let next_back = self.back.saturating_add(1);
let index = self.junctions.len().checked_sub(next_back)?;
if self.next > index {
return None
}
self.back = next_back;
self.junctions.at(index)
}
}
impl<'a> IntoIterator for &'a Junctions {
type Item = &'a Junction;
type IntoIter = JunctionsRefIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
JunctionsRefIterator { junctions: self, next: 0, back: 0 }
}
}
impl IntoIterator for Junctions {
type Item = Junction;
type IntoIter = JunctionsIterator;
fn into_iter(self) -> Self::IntoIter {
JunctionsIterator(self)
}
}
impl Junctions {
pub const fn into(self) -> MultiLocation {
MultiLocation { parents: 0, interior: self }
}
pub const fn into_exterior(self, n: u8) -> MultiLocation {
MultiLocation { parents: n, interior: self }
}
pub fn first(&self) -> Option<&Junction> {
match &self {
Junctions::Here => None,
Junctions::X1(ref a) => Some(a),
Junctions::X2(ref a, ..) => Some(a),
Junctions::X3(ref a, ..) => Some(a),
Junctions::X4(ref a, ..) => Some(a),
Junctions::X5(ref a, ..) => Some(a),
Junctions::X6(ref a, ..) => Some(a),
Junctions::X7(ref a, ..) => Some(a),
Junctions::X8(ref a, ..) => Some(a),
}
}
pub fn last(&self) -> Option<&Junction> {
match &self {
Junctions::Here => None,
Junctions::X1(ref a) => Some(a),
Junctions::X2(.., ref a) => Some(a),
Junctions::X3(.., ref a) => Some(a),
Junctions::X4(.., ref a) => Some(a),
Junctions::X5(.., ref a) => Some(a),
Junctions::X6(.., ref a) => Some(a),
Junctions::X7(.., ref a) => Some(a),
Junctions::X8(.., ref a) => Some(a),
}
}
pub fn split_first(self) -> (Junctions, Option<Junction>) {
match self {
Junctions::Here => (Junctions::Here, None),
Junctions::X1(a) => (Junctions::Here, Some(a)),
Junctions::X2(a, b) => (Junctions::X1(b), Some(a)),
Junctions::X3(a, b, c) => (Junctions::X2(b, c), Some(a)),
Junctions::X4(a, b, c, d) => (Junctions::X3(b, c, d), Some(a)),
Junctions::X5(a, b, c, d, e) => (Junctions::X4(b, c, d, e), Some(a)),
Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(b, c, d, e, f), Some(a)),
Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(b, c, d, e, f, g), Some(a)),
Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(b, c, d, e, f, g, h), Some(a)),
}
}
pub fn split_last(self) -> (Junctions, Option<Junction>) {
match self {
Junctions::Here => (Junctions::Here, None),
Junctions::X1(a) => (Junctions::Here, Some(a)),
Junctions::X2(a, b) => (Junctions::X1(a), Some(b)),
Junctions::X3(a, b, c) => (Junctions::X2(a, b), Some(c)),
Junctions::X4(a, b, c, d) => (Junctions::X3(a, b, c), Some(d)),
Junctions::X5(a, b, c, d, e) => (Junctions::X4(a, b, c, d), Some(e)),
Junctions::X6(a, b, c, d, e, f) => (Junctions::X5(a, b, c, d, e), Some(f)),
Junctions::X7(a, b, c, d, e, f, g) => (Junctions::X6(a, b, c, d, e, f), Some(g)),
Junctions::X8(a, b, c, d, e, f, g, h) => (Junctions::X7(a, b, c, d, e, f, g), Some(h)),
}
}
pub fn take_first(&mut self) -> Option<Junction> {
let mut d = Junctions::Here;
mem::swap(&mut *self, &mut d);
let (tail, head) = d.split_first();
*self = tail;
head
}
pub fn take_last(&mut self) -> Option<Junction> {
let mut d = Junctions::Here;
mem::swap(&mut *self, &mut d);
let (head, tail) = d.split_last();
*self = head;
tail
}
pub fn push(&mut self, new: Junction) -> result::Result<(), Junction> {
let mut dummy = Junctions::Here;
mem::swap(self, &mut dummy);
match dummy.pushed_with(new) {
Ok(s) => {
*self = s;
Ok(())
},
Err((s, j)) => {
*self = s;
Err(j)
},
}
}
pub fn push_front(&mut self, new: Junction) -> result::Result<(), Junction> {
let mut dummy = Junctions::Here;
mem::swap(self, &mut dummy);
match dummy.pushed_front_with(new) {
Ok(s) => {
*self = s;
Ok(())
},
Err((s, j)) => {
*self = s;
Err(j)
},
}
}
pub fn pushed_with(self, new: Junction) -> result::Result<Self, (Self, Junction)> {
Ok(match self {
Junctions::Here => Junctions::X1(new),
Junctions::X1(a) => Junctions::X2(a, new),
Junctions::X2(a, b) => Junctions::X3(a, b, new),
Junctions::X3(a, b, c) => Junctions::X4(a, b, c, new),
Junctions::X4(a, b, c, d) => Junctions::X5(a, b, c, d, new),
Junctions::X5(a, b, c, d, e) => Junctions::X6(a, b, c, d, e, new),
Junctions::X6(a, b, c, d, e, f) => Junctions::X7(a, b, c, d, e, f, new),
Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(a, b, c, d, e, f, g, new),
s => Err((s, new))?,
})
}
pub fn pushed_front_with(self, new: Junction) -> result::Result<Self, (Self, Junction)> {
Ok(match self {
Junctions::Here => Junctions::X1(new),
Junctions::X1(a) => Junctions::X2(new, a),
Junctions::X2(a, b) => Junctions::X3(new, a, b),
Junctions::X3(a, b, c) => Junctions::X4(new, a, b, c),
Junctions::X4(a, b, c, d) => Junctions::X5(new, a, b, c, d),
Junctions::X5(a, b, c, d, e) => Junctions::X6(new, a, b, c, d, e),
Junctions::X6(a, b, c, d, e, f) => Junctions::X7(new, a, b, c, d, e, f),
Junctions::X7(a, b, c, d, e, f, g) => Junctions::X8(new, a, b, c, d, e, f, g),
s => Err((s, new))?,
})
}
pub const fn len(&self) -> usize {
match &self {
Junctions::Here => 0,
Junctions::X1(..) => 1,
Junctions::X2(..) => 2,
Junctions::X3(..) => 3,
Junctions::X4(..) => 4,
Junctions::X5(..) => 5,
Junctions::X6(..) => 6,
Junctions::X7(..) => 7,
Junctions::X8(..) => 8,
}
}
pub fn at(&self, i: usize) -> Option<&Junction> {
Some(match (i, self) {
(0, Junctions::X1(ref a)) => a,
(0, Junctions::X2(ref a, ..)) => a,
(0, Junctions::X3(ref a, ..)) => a,
(0, Junctions::X4(ref a, ..)) => a,
(0, Junctions::X5(ref a, ..)) => a,
(0, Junctions::X6(ref a, ..)) => a,
(0, Junctions::X7(ref a, ..)) => a,
(0, Junctions::X8(ref a, ..)) => a,
(1, Junctions::X2(_, ref a)) => a,
(1, Junctions::X3(_, ref a, ..)) => a,
(1, Junctions::X4(_, ref a, ..)) => a,
(1, Junctions::X5(_, ref a, ..)) => a,
(1, Junctions::X6(_, ref a, ..)) => a,
(1, Junctions::X7(_, ref a, ..)) => a,
(1, Junctions::X8(_, ref a, ..)) => a,
(2, Junctions::X3(_, _, ref a)) => a,
(2, Junctions::X4(_, _, ref a, ..)) => a,
(2, Junctions::X5(_, _, ref a, ..)) => a,
(2, Junctions::X6(_, _, ref a, ..)) => a,
(2, Junctions::X7(_, _, ref a, ..)) => a,
(2, Junctions::X8(_, _, ref a, ..)) => a,
(3, Junctions::X4(_, _, _, ref a)) => a,
(3, Junctions::X5(_, _, _, ref a, ..)) => a,
(3, Junctions::X6(_, _, _, ref a, ..)) => a,
(3, Junctions::X7(_, _, _, ref a, ..)) => a,
(3, Junctions::X8(_, _, _, ref a, ..)) => a,
(4, Junctions::X5(_, _, _, _, ref a)) => a,
(4, Junctions::X6(_, _, _, _, ref a, ..)) => a,
(4, Junctions::X7(_, _, _, _, ref a, ..)) => a,
(4, Junctions::X8(_, _, _, _, ref a, ..)) => a,
(5, Junctions::X6(_, _, _, _, _, ref a)) => a,
(5, Junctions::X7(_, _, _, _, _, ref a, ..)) => a,
(5, Junctions::X8(_, _, _, _, _, ref a, ..)) => a,
(6, Junctions::X7(_, _, _, _, _, _, ref a)) => a,
(6, Junctions::X8(_, _, _, _, _, _, ref a, ..)) => a,
(7, Junctions::X8(_, _, _, _, _, _, _, ref a)) => a,
_ => return None,
})
}
pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
Some(match (i, self) {
(0, Junctions::X1(ref mut a)) => a,
(0, Junctions::X2(ref mut a, ..)) => a,
(0, Junctions::X3(ref mut a, ..)) => a,
(0, Junctions::X4(ref mut a, ..)) => a,
(0, Junctions::X5(ref mut a, ..)) => a,
(0, Junctions::X6(ref mut a, ..)) => a,
(0, Junctions::X7(ref mut a, ..)) => a,
(0, Junctions::X8(ref mut a, ..)) => a,
(1, Junctions::X2(_, ref mut a)) => a,
(1, Junctions::X3(_, ref mut a, ..)) => a,
(1, Junctions::X4(_, ref mut a, ..)) => a,
(1, Junctions::X5(_, ref mut a, ..)) => a,
(1, Junctions::X6(_, ref mut a, ..)) => a,
(1, Junctions::X7(_, ref mut a, ..)) => a,
(1, Junctions::X8(_, ref mut a, ..)) => a,
(2, Junctions::X3(_, _, ref mut a)) => a,
(2, Junctions::X4(_, _, ref mut a, ..)) => a,
(2, Junctions::X5(_, _, ref mut a, ..)) => a,
(2, Junctions::X6(_, _, ref mut a, ..)) => a,
(2, Junctions::X7(_, _, ref mut a, ..)) => a,
(2, Junctions::X8(_, _, ref mut a, ..)) => a,
(3, Junctions::X4(_, _, _, ref mut a)) => a,
(3, Junctions::X5(_, _, _, ref mut a, ..)) => a,
(3, Junctions::X6(_, _, _, ref mut a, ..)) => a,
(3, Junctions::X7(_, _, _, ref mut a, ..)) => a,
(3, Junctions::X8(_, _, _, ref mut a, ..)) => a,
(4, Junctions::X5(_, _, _, _, ref mut a)) => a,
(4, Junctions::X6(_, _, _, _, ref mut a, ..)) => a,
(4, Junctions::X7(_, _, _, _, ref mut a, ..)) => a,
(4, Junctions::X8(_, _, _, _, ref mut a, ..)) => a,
(5, Junctions::X6(_, _, _, _, _, ref mut a)) => a,
(5, Junctions::X7(_, _, _, _, _, ref mut a, ..)) => a,
(5, Junctions::X8(_, _, _, _, _, ref mut a, ..)) => a,
(6, Junctions::X7(_, _, _, _, _, _, ref mut a)) => a,
(6, Junctions::X8(_, _, _, _, _, _, ref mut a, ..)) => a,
(7, Junctions::X8(_, _, _, _, _, _, _, ref mut a)) => a,
_ => return None,
})
}
pub fn iter(&self) -> JunctionsRefIterator {
JunctionsRefIterator { junctions: self, next: 0, back: 0 }
}
#[deprecated(note = "Please use iter().rev()")]
pub fn iter_rev(&self) -> impl Iterator + '_ {
self.iter().rev()
}
#[deprecated(note = "Please use into_iter().rev()")]
pub fn into_iter_rev(self) -> impl Iterator {
self.into_iter().rev()
}
pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> {
if prefix.len() + 1 != self.len() || !self.starts_with(prefix) {
return None
}
self.at(prefix.len())
}
pub fn starts_with(&self, prefix: &Junctions) -> bool {
if self.len() < prefix.len() {
return false
}
prefix.iter().zip(self.iter()).all(|(l, r)| l == r)
}
}
impl TryFrom<MultiLocation> for Junctions {
type Error = ();
fn try_from(x: MultiLocation) -> result::Result<Self, ()> {
if x.parents > 0 {
Err(())
} else {
Ok(x.interior)
}
}
}
#[cfg(test)]
mod tests {
use super::{Ancestor, AncestorThen, Junctions::*, MultiLocation, Parent, ParentThen};
use crate::opaque::v2::{Junction::*, NetworkId::*};
use parity_scale_codec::{Decode, Encode};
#[test]
fn inverted_works() {
let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42)).into();
let target = (Parent, PalletInstance(69)).into();
let expected = (Parent, PalletInstance(42)).into();
let inverted = ancestry.inverted(&target).unwrap();
assert_eq!(inverted, expected);
let ancestry: MultiLocation = (Parachain(1000), PalletInstance(42), GeneralIndex(1)).into();
let target = (Parent, Parent, PalletInstance(69), GeneralIndex(2)).into();
let expected = (Parent, Parent, PalletInstance(42), GeneralIndex(1)).into();
let inverted = ancestry.inverted(&target).unwrap();
assert_eq!(inverted, expected);
}
#[test]
fn simplify_basic_works() {
let mut location: MultiLocation =
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
let context = X2(Parachain(1000), PalletInstance(42));
let expected = GeneralIndex(69).into();
location.simplify(&context);
assert_eq!(location, expected);
let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
let context = X1(PalletInstance(42));
let expected = GeneralIndex(69).into();
location.simplify(&context);
assert_eq!(location, expected);
let mut location: MultiLocation = (Parent, PalletInstance(42), GeneralIndex(69)).into();
let context = X2(Parachain(1000), PalletInstance(42));
let expected = GeneralIndex(69).into();
location.simplify(&context);
assert_eq!(location, expected);
let mut location: MultiLocation =
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
let context = X3(OnlyChild, Parachain(1000), PalletInstance(42));
let expected = GeneralIndex(69).into();
location.simplify(&context);
assert_eq!(location, expected);
}
#[test]
fn simplify_incompatible_location_fails() {
let mut location: MultiLocation =
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
let context = X3(Parachain(1000), PalletInstance(42), GeneralIndex(42));
let expected =
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
location.simplify(&context);
assert_eq!(location, expected);
let mut location: MultiLocation =
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
let context = X1(Parachain(1000));
let expected =
(Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
location.simplify(&context);
assert_eq!(location, expected);
}
#[test]
fn reanchor_works() {
let mut id: MultiLocation = (Parent, Parachain(1000), GeneralIndex(42)).into();
let ancestry = Parachain(2000).into();
let target = (Parent, Parachain(1000)).into();
let expected = GeneralIndex(42).into();
id.reanchor(&target, &ancestry).unwrap();
assert_eq!(id, expected);
}
#[test]
fn encode_and_decode_works() {
let m = MultiLocation {
parents: 1,
interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }),
};
let encoded = m.encode();
assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec());
let decoded = MultiLocation::decode(&mut &encoded[..]);
assert_eq!(decoded, Ok(m));
}
#[test]
fn match_and_split_works() {
let m = MultiLocation {
parents: 1,
interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }),
};
assert_eq!(m.match_and_split(&MultiLocation { parents: 1, interior: Here }), None);
assert_eq!(
m.match_and_split(&MultiLocation { parents: 1, interior: X1(Parachain(42)) }),
Some(&AccountIndex64 { network: Any, index: 23 })
);
assert_eq!(m.match_and_split(&m), None);
}
#[test]
fn starts_with_works() {
let full: MultiLocation =
(Parent, Parachain(1000), AccountId32 { network: Any, id: [0; 32] }).into();
let identity: MultiLocation = full.clone();
let prefix: MultiLocation = (Parent, Parachain(1000)).into();
let wrong_parachain: MultiLocation = (Parent, Parachain(1001)).into();
let wrong_account: MultiLocation =
(Parent, Parachain(1000), AccountId32 { network: Any, id: [1; 32] }).into();
let no_parents: MultiLocation = (Parachain(1000)).into();
let too_many_parents: MultiLocation = (Parent, Parent, Parachain(1000)).into();
assert!(full.starts_with(&identity));
assert!(full.starts_with(&prefix));
assert!(!full.starts_with(&wrong_parachain));
assert!(!full.starts_with(&wrong_account));
assert!(!full.starts_with(&no_parents));
assert!(!full.starts_with(&too_many_parents));
}
#[test]
fn append_with_works() {
let acc = AccountIndex64 { network: Any, index: 23 };
let mut m = MultiLocation { parents: 1, interior: X1(Parachain(42)) };
assert_eq!(m.append_with(X2(PalletInstance(3), acc.clone())), Ok(()));
assert_eq!(
m,
MultiLocation {
parents: 1,
interior: X3(Parachain(42), PalletInstance(3), acc.clone())
}
);
let acc = AccountIndex64 { network: Any, index: 23 };
let m = MultiLocation {
parents: 254,
interior: X5(Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild),
};
let suffix = X4(PalletInstance(3), acc.clone(), OnlyChild, OnlyChild);
assert_eq!(m.clone().append_with(suffix.clone()), Err(suffix));
}
#[test]
fn prepend_with_works() {
let mut m = MultiLocation {
parents: 1,
interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 }),
};
assert_eq!(m.prepend_with(MultiLocation { parents: 1, interior: X1(OnlyChild) }), Ok(()));
assert_eq!(
m,
MultiLocation {
parents: 1,
interior: X2(Parachain(42), AccountIndex64 { network: Any, index: 23 })
}
);
let mut m = MultiLocation { parents: 254, interior: X1(Parachain(42)) };
let prefix = MultiLocation { parents: 2, interior: Here };
assert_eq!(m.prepend_with(prefix.clone()), Err(prefix));
let prefix = MultiLocation { parents: 1, interior: Here };
assert_eq!(m.prepend_with(prefix), Ok(()));
assert_eq!(m, MultiLocation { parents: 255, interior: X1(Parachain(42)) });
}
#[test]
fn double_ended_ref_iteration_works() {
let m = X3(Parachain(1000), Parachain(3), PalletInstance(5));
let mut iter = m.iter();
let first = iter.next().unwrap();
assert_eq!(first, &Parachain(1000));
let third = iter.next_back().unwrap();
assert_eq!(third, &PalletInstance(5));
let second = iter.next_back().unwrap();
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
assert_eq!(second, &Parachain(3));
let res = Here
.pushed_with(first.clone())
.unwrap()
.pushed_with(second.clone())
.unwrap()
.pushed_with(third.clone())
.unwrap();
assert_eq!(m, res);
let m = Here;
let mut iter = m.iter();
assert_eq!(iter.next(), None);
assert_eq!(iter.next_back(), None);
}
#[test]
fn conversion_from_other_types_works() {
fn takes_multilocation<Arg: Into<MultiLocation>>(_arg: Arg) {}
takes_multilocation(Parent);
takes_multilocation(Here);
takes_multilocation(X1(Parachain(42)));
takes_multilocation((255, PalletInstance(8)));
takes_multilocation((Ancestor(5), Parachain(1), PalletInstance(3)));
takes_multilocation((Ancestor(2), Here));
takes_multilocation(AncestorThen(
3,
X2(Parachain(43), AccountIndex64 { network: Any, index: 155 }),
));
takes_multilocation((Parent, AccountId32 { network: Any, id: [0; 32] }));
takes_multilocation((Parent, Here));
takes_multilocation(ParentThen(X1(Parachain(75))));
takes_multilocation([Parachain(100), PalletInstance(3)]);
}
}