Add starts_with to v0 and v1 MultiLocation (#6311)

* add `starts_with` to v0 and v1 MultiLocation

* add tests

* fmt
This commit is contained in:
joe petrowski
2022-11-20 17:31:06 +01:00
committed by GitHub
parent 9c2561f07a
commit 8456b2ec90
2 changed files with 95 additions and 12 deletions
+37 -6
View File
@@ -356,17 +356,30 @@ impl MultiLocation {
/// # }
/// ```
pub fn match_and_split(&self, prefix: &MultiLocation) -> Option<&Junction> {
if prefix.len() + 1 != self.len() {
if prefix.len() + 1 != self.len() || !self.starts_with(prefix) {
return None
}
for i in 0..prefix.len() {
if prefix.at(i) != self.at(i) {
return None
}
}
return self.at(prefix.len())
}
/// Returns whether `self` begins with or is equal to `prefix`.
///
/// # Example
/// ```rust
/// # use xcm::v0::{Junction::*, MultiLocation::*};
/// let m = X4(Parent, PalletInstance(3), OnlyChild, OnlyChild);
/// assert!(m.starts_with(&X2(Parent, PalletInstance(3))));
/// assert!(m.starts_with(&m));
/// assert!(!m.starts_with(&X2(Parent, GeneralIndex(99))));
/// assert!(!m.starts_with(&X1(PalletInstance(3))));
/// ```
pub fn starts_with(&self, prefix: &MultiLocation) -> bool {
if self.len() < prefix.len() {
return false
}
prefix.iter().zip(self.iter()).all(|(l, r)| l == r)
}
/// Mutates `self`, suffixing it with `new`. Returns `Err` in case of overflow.
pub fn push(&mut self, new: Junction) -> result::Result<(), ()> {
let mut n = MultiLocation::Null;
@@ -601,6 +614,24 @@ mod tests {
assert_eq!(m.match_and_split(&m), None);
}
#[test]
fn starts_with_works() {
let full = X3(Parent, Parachain(1000), AccountIndex64 { network: Any, index: 23 });
let identity = full.clone();
let prefix = X2(Parent, Parachain(1000));
let wrong_parachain = X2(Parent, Parachain(1001));
let wrong_account = X3(Parent, Parachain(1000), AccountIndex64 { network: Any, index: 24 });
let no_parents = X1(Parachain(1000));
let too_many_parents = X3(Parent, Parent, Parachain(1000));
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 };
+57 -5
View File
@@ -253,6 +253,24 @@ impl MultiLocation {
self.interior.match_and_split(&prefix.interior)
}
/// Returns whether `self` has the same number of parents as `prefix` and its junctions begins
/// with the junctions of `prefix`.
///
/// # Example
/// ```rust
/// # use xcm::v1::{Junctions::*, Junction::*, MultiLocation};
/// let m = MultiLocation::new(1, X3(PalletInstance(3), OnlyChild, OnlyChild));
/// assert!(m.starts_with(&MultiLocation::new(1, X1(PalletInstance(3)))));
/// assert!(!m.starts_with(&MultiLocation::new(1, X1(GeneralIndex(99)))));
/// assert!(!m.starts_with(&MultiLocation::new(0, X1(PalletInstance(3)))));
/// ```
pub fn starts_with(&self, prefix: &MultiLocation) -> bool {
if self.parents != prefix.parents {
return false
}
self.interior.starts_with(&prefix.interior)
}
/// Mutate `self` so that it is suffixed with `suffix`.
///
/// Does not modify `self` and returns `Err` with `suffix` in case of overflow.
@@ -801,15 +819,29 @@ impl Junctions {
/// # }
/// ```
pub fn match_and_split(&self, prefix: &Junctions) -> Option<&Junction> {
if prefix.len() + 1 != self.len() {
if prefix.len() + 1 != self.len() || !self.starts_with(prefix) {
return None
}
for i in 0..prefix.len() {
if prefix.at(i) != self.at(i) {
return None
self.at(prefix.len())
}
/// Returns whether `self` begins with or is equal to `prefix`.
///
/// # Example
/// ```rust
/// # use xcm::v1::{Junctions::*, Junction::*};
/// let mut j = X3(Parachain(2), PalletInstance(3), OnlyChild);
/// assert!(j.starts_with(&X2(Parachain(2), PalletInstance(3))));
/// assert!(j.starts_with(&j));
/// assert!(j.starts_with(&X1(Parachain(2))));
/// assert!(!j.starts_with(&X1(Parachain(999))));
/// assert!(!j.starts_with(&X4(Parachain(2), PalletInstance(3), OnlyChild, OnlyChild)));
/// ```
pub fn starts_with(&self, prefix: &Junctions) -> bool {
if self.len() < prefix.len() {
return false
}
return self.at(prefix.len())
prefix.iter().zip(self.iter()).all(|(l, r)| l == r)
}
}
@@ -929,6 +961,26 @@ mod tests {
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 };