1use super::{traits::Reanchorable, Junction, Junctions};
20use crate::{v4::Location as OldLocation, VersionedLocation};
21use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
22use core::result;
23use scale_info::TypeInfo;
24
25#[derive(
52 Clone,
53 Decode,
54 Encode,
55 DecodeWithMemTracking,
56 Eq,
57 PartialEq,
58 Ord,
59 PartialOrd,
60 Debug,
61 TypeInfo,
62 MaxEncodedLen,
63 serde::Serialize,
64 serde::Deserialize,
65)]
66pub struct Location {
67 pub parents: u8,
69 pub interior: Junctions,
71}
72
73impl Default for Location {
74 fn default() -> Self {
75 Self::here()
76 }
77}
78
79pub type InteriorLocation = Junctions;
83
84impl Location {
85 pub fn new(parents: u8, interior: impl Into<Junctions>) -> Location {
87 Location { parents, interior: interior.into() }
88 }
89
90 pub const fn into_versioned(self) -> VersionedLocation {
92 VersionedLocation::V5(self)
93 }
94
95 pub const fn here() -> Location {
99 Location { parents: 0, interior: Junctions::Here }
100 }
101
102 pub const fn parent() -> Location {
104 Location { parents: 1, interior: Junctions::Here }
105 }
106
107 pub const fn ancestor(parents: u8) -> Location {
109 Location { parents, interior: Junctions::Here }
110 }
111
112 pub fn is_here(&self) -> bool {
114 self.parents == 0 && self.interior.len() == 0
115 }
116
117 pub fn remove_network_id(&mut self) {
119 self.interior.remove_network_id();
120 }
121
122 pub fn interior(&self) -> &Junctions {
124 &self.interior
125 }
126
127 pub fn interior_mut(&mut self) -> &mut Junctions {
129 &mut self.interior
130 }
131
132 pub const fn parent_count(&self) -> u8 {
134 self.parents
135 }
136
137 pub fn unpack(&self) -> (u8, &[Junction]) {
151 (self.parents, self.interior.as_slice())
152 }
153
154 pub const fn contains_parents_only(&self, count: u8) -> bool {
157 matches!(self.interior, Junctions::Here) && self.parents == count
158 }
159
160 pub fn len(&self) -> usize {
162 self.parent_count() as usize + self.interior.len()
163 }
164
165 pub fn first_interior(&self) -> Option<&Junction> {
168 self.interior.first()
169 }
170
171 pub fn last(&self) -> Option<&Junction> {
173 self.interior.last()
174 }
175
176 pub fn split_first_interior(self) -> (Location, Option<Junction>) {
179 let Location { parents, interior: junctions } = self;
180 let (suffix, first) = junctions.split_first();
181 let location = Location { parents, interior: suffix };
182 (location, first)
183 }
184
185 pub fn split_last_interior(self) -> (Location, Option<Junction>) {
189 let Location { parents, interior: junctions } = self;
190 let (prefix, last) = junctions.split_last();
191 let location = Location { parents, interior: prefix };
192 (location, last)
193 }
194
195 pub fn push_interior(&mut self, new: impl Into<Junction>) -> result::Result<(), Junction> {
198 self.interior.push(new)
199 }
200
201 pub fn push_front_interior(
204 &mut self,
205 new: impl Into<Junction>,
206 ) -> result::Result<(), Junction> {
207 self.interior.push_front(new)
208 }
209
210 pub fn pushed_with_interior(
213 self,
214 new: impl Into<Junction>,
215 ) -> result::Result<Self, (Self, Junction)> {
216 match self.interior.pushed_with(new) {
217 Ok(i) => Ok(Location { interior: i, parents: self.parents }),
218 Err((i, j)) => Err((Location { interior: i, parents: self.parents }, j)),
219 }
220 }
221
222 pub fn pushed_front_with_interior(
225 self,
226 new: impl Into<Junction>,
227 ) -> result::Result<Self, (Self, Junction)> {
228 match self.interior.pushed_front_with(new) {
229 Ok(i) => Ok(Location { interior: i, parents: self.parents }),
230 Err((i, j)) => Err((Location { interior: i, parents: self.parents }, j)),
231 }
232 }
233
234 pub fn at(&self, i: usize) -> Option<&Junction> {
237 let num_parents = self.parents as usize;
238 if i < num_parents {
239 return None
240 }
241 self.interior.at(i - num_parents)
242 }
243
244 pub fn at_mut(&mut self, i: usize) -> Option<&mut Junction> {
247 let num_parents = self.parents as usize;
248 if i < num_parents {
249 return None
250 }
251 self.interior.at_mut(i - num_parents)
252 }
253
254 pub fn dec_parent(&mut self) {
256 self.parents = self.parents.saturating_sub(1);
257 }
258
259 pub fn take_first_interior(&mut self) -> Option<Junction> {
262 self.interior.take_first()
263 }
264
265 pub fn take_last(&mut self) -> Option<Junction> {
268 self.interior.take_last()
269 }
270
271 pub fn match_and_split(&self, prefix: &Location) -> Option<&Junction> {
288 if self.parents != prefix.parents {
289 return None
290 }
291 self.interior.match_and_split(&prefix.interior)
292 }
293
294 pub fn starts_with(&self, prefix: &Location) -> bool {
295 self.parents == prefix.parents && self.interior.starts_with(&prefix.interior)
296 }
297
298 pub fn append_with(&mut self, suffix: impl Into<Self>) -> Result<(), Self> {
312 let prefix = core::mem::replace(self, suffix.into());
313 match self.prepend_with(prefix) {
314 Ok(()) => Ok(()),
315 Err(prefix) => Err(core::mem::replace(self, prefix)),
316 }
317 }
318
319 pub fn appended_with(mut self, suffix: impl Into<Self>) -> Result<Self, (Self, Self)> {
333 match self.append_with(suffix) {
334 Ok(()) => Ok(self),
335 Err(suffix) => Err((self, suffix)),
336 }
337 }
338
339 pub fn prepend_with(&mut self, prefix: impl Into<Self>) -> Result<(), Self> {
353 let mut prefix = prefix.into();
356 let prepend_interior = prefix.interior.len().saturating_sub(self.parents as usize);
357 let final_interior = self.interior.len().saturating_add(prepend_interior);
358 if final_interior > super::junctions::MAX_JUNCTIONS {
359 return Err(prefix)
360 }
361 let suffix_parents = (self.parents as usize).saturating_sub(prefix.interior.len());
362 let final_parents = (prefix.parents as usize).saturating_add(suffix_parents);
363 if final_parents > 255 {
364 return Err(prefix)
365 }
366
367 while self.parents > 0 && prefix.take_last().is_some() {
369 self.dec_parent();
370 }
371
372 self.parents = self.parents.saturating_add(prefix.parents);
381 for j in prefix.interior.into_iter().rev() {
382 self.push_front_interior(j)
383 .expect("final_interior no greater than MAX_JUNCTIONS; qed");
384 }
385 Ok(())
386 }
387
388 pub fn prepended_with(mut self, prefix: impl Into<Self>) -> Result<Self, (Self, Self)> {
402 match self.prepend_with(prefix) {
403 Ok(()) => Ok(self),
404 Err(prefix) => Err((self, prefix)),
405 }
406 }
407
408 pub fn simplify(&mut self, context: &Junctions) {
411 if context.len() < self.parents as usize {
412 return
414 }
415 while self.parents > 0 {
416 let maybe = context.at(context.len() - (self.parents as usize));
417 match (self.interior.first(), maybe) {
418 (Some(i), Some(j)) if i == j => {
419 self.interior.take_first();
420 self.parents -= 1;
421 },
422 _ => break,
423 }
424 }
425 }
426
427 pub fn chain_location(&self) -> Location {
429 let mut clone = self.clone();
430 while let Some(j) = clone.last() {
432 if matches!(j, Junction::Parachain(_) | Junction::GlobalConsensus(_)) {
433 return clone
435 } else {
436 (clone, _) = clone.split_last_interior();
437 }
438 }
439 Location::new(clone.parents, Junctions::Here)
440 }
441}
442
443impl Reanchorable for Location {
444 type Error = Self;
445
446 fn reanchor(&mut self, target: &Location, context: &InteriorLocation) -> Result<(), ()> {
451 let inverted_target = context.invert_target(target)?;
455
456 self.prepend_with(inverted_target).map_err(|_| ())?;
459
460 self.simplify(target.interior());
463
464 Ok(())
465 }
466
467 fn reanchored(mut self, target: &Location, context: &InteriorLocation) -> Result<Self, Self> {
472 match self.reanchor(target, context) {
473 Ok(()) => Ok(self),
474 Err(()) => Err(self),
475 }
476 }
477}
478
479impl TryFrom<OldLocation> for Option<Location> {
480 type Error = ();
481 fn try_from(value: OldLocation) -> result::Result<Self, Self::Error> {
482 Ok(Some(Location::try_from(value)?))
483 }
484}
485
486impl TryFrom<OldLocation> for Location {
487 type Error = ();
488 fn try_from(x: OldLocation) -> result::Result<Self, ()> {
489 Ok(Location { parents: x.parents, interior: x.interior.try_into()? })
490 }
491}
492
493#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
495pub struct Parent;
496impl From<Parent> for Location {
497 fn from(_: Parent) -> Self {
498 Location { parents: 1, interior: Junctions::Here }
499 }
500}
501
502#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
505pub struct ParentThen(pub Junctions);
506impl From<ParentThen> for Location {
507 fn from(ParentThen(interior): ParentThen) -> Self {
508 Location { parents: 1, interior }
509 }
510}
511
512#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
514pub struct Ancestor(pub u8);
515impl From<Ancestor> for Location {
516 fn from(Ancestor(parents): Ancestor) -> Self {
517 Location { parents, interior: Junctions::Here }
518 }
519}
520
521#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
524pub struct AncestorThen<Interior>(pub u8, pub Interior);
525impl<Interior: Into<Junctions>> From<AncestorThen<Interior>> for Location {
526 fn from(AncestorThen(parents, interior): AncestorThen<Interior>) -> Self {
527 Location { parents, interior: interior.into() }
528 }
529}
530
531impl From<[u8; 32]> for Location {
532 fn from(bytes: [u8; 32]) -> Self {
533 let junction: Junction = bytes.into();
534 junction.into()
535 }
536}
537
538impl From<sp_runtime::AccountId32> for Location {
539 fn from(id: sp_runtime::AccountId32) -> Self {
540 Junction::AccountId32 { network: None, id: id.into() }.into()
541 }
542}
543
544xcm_procedural::impl_conversion_functions_for_location_v5!();
545
546#[cfg(test)]
547mod tests {
548 use crate::v5::prelude::*;
549 use codec::{Decode, Encode};
550
551 #[test]
552 fn conversion_works() {
553 let x: Location = Parent.into();
554 assert_eq!(x, Location { parents: 1, interior: Here });
555 let x: Location = (Parent, Parent, OnlyChild).into();
560 assert_eq!(x, Location { parents: 2, interior: OnlyChild.into() });
561 let x: Location = OnlyChild.into();
562 assert_eq!(x, Location { parents: 0, interior: OnlyChild.into() });
563 let x: Location = (OnlyChild,).into();
564 assert_eq!(x, Location { parents: 0, interior: OnlyChild.into() });
565 }
566
567 #[test]
568 fn simplify_basic_works() {
569 let mut location: Location =
570 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
571 let context = [Parachain(1000), PalletInstance(42)].into();
572 let expected = GeneralIndex(69).into();
573 location.simplify(&context);
574 assert_eq!(location, expected);
575
576 let mut location: Location = (Parent, PalletInstance(42), GeneralIndex(69)).into();
577 let context = [PalletInstance(42)].into();
578 let expected = GeneralIndex(69).into();
579 location.simplify(&context);
580 assert_eq!(location, expected);
581
582 let mut location: Location = (Parent, PalletInstance(42), GeneralIndex(69)).into();
583 let context = [Parachain(1000), PalletInstance(42)].into();
584 let expected = GeneralIndex(69).into();
585 location.simplify(&context);
586 assert_eq!(location, expected);
587
588 let mut location: Location =
589 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
590 let context = [OnlyChild, Parachain(1000), PalletInstance(42)].into();
591 let expected = GeneralIndex(69).into();
592 location.simplify(&context);
593 assert_eq!(location, expected);
594 }
595
596 #[test]
597 fn simplify_incompatible_location_fails() {
598 let mut location: Location =
599 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
600 let context = [Parachain(1000), PalletInstance(42), GeneralIndex(42)].into();
601 let expected =
602 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
603 location.simplify(&context);
604 assert_eq!(location, expected);
605
606 let mut location: Location =
607 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
608 let context = [Parachain(1000)].into();
609 let expected =
610 (Parent, Parent, Parachain(1000), PalletInstance(42), GeneralIndex(69)).into();
611 location.simplify(&context);
612 assert_eq!(location, expected);
613 }
614
615 #[test]
616 fn reanchor_works() {
617 let mut id: Location = (Parent, Parachain(1000), GeneralIndex(42)).into();
618 let context = Parachain(2000).into();
619 let target = (Parent, Parachain(1000)).into();
620 let expected = GeneralIndex(42).into();
621 id.reanchor(&target, &context).unwrap();
622 assert_eq!(id, expected);
623 }
624
625 #[test]
626 fn encode_and_decode_works() {
627 let m = Location {
628 parents: 1,
629 interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
630 };
631 let encoded = m.encode();
632 assert_eq!(encoded, [1, 2, 0, 168, 2, 0, 92].to_vec());
633 let decoded = Location::decode(&mut &encoded[..]);
634 assert_eq!(decoded, Ok(m));
635 }
636
637 #[test]
638 fn match_and_split_works() {
639 let m = Location {
640 parents: 1,
641 interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
642 };
643 assert_eq!(m.match_and_split(&Location { parents: 1, interior: Here }), None);
644 assert_eq!(
645 m.match_and_split(&Location { parents: 1, interior: [Parachain(42)].into() }),
646 Some(&AccountIndex64 { network: None, index: 23 })
647 );
648 assert_eq!(m.match_and_split(&m), None);
649 }
650
651 #[test]
652 fn append_with_works() {
653 let acc = AccountIndex64 { network: None, index: 23 };
654 let mut m = Location { parents: 1, interior: [Parachain(42)].into() };
655 assert_eq!(m.append_with([PalletInstance(3), acc]), Ok(()));
656 assert_eq!(
657 m,
658 Location { parents: 1, interior: [Parachain(42), PalletInstance(3), acc].into() }
659 );
660
661 let acc = AccountIndex64 { network: None, index: 23 };
663 let m = Location {
664 parents: 254,
665 interior: [Parachain(42), OnlyChild, OnlyChild, OnlyChild, OnlyChild].into(),
666 };
667 let suffix: Location = (PalletInstance(3), acc, OnlyChild, OnlyChild).into();
668 assert_eq!(m.clone().append_with(suffix.clone()), Err(suffix));
669 }
670
671 #[test]
672 fn prepend_with_works() {
673 let mut m = Location {
674 parents: 1,
675 interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into(),
676 };
677 assert_eq!(m.prepend_with(Location { parents: 1, interior: [OnlyChild].into() }), Ok(()));
678 assert_eq!(
679 m,
680 Location {
681 parents: 1,
682 interior: [Parachain(42), AccountIndex64 { network: None, index: 23 }].into()
683 }
684 );
685
686 let mut m = Location { parents: 254, interior: [Parachain(42)].into() };
688 let prefix = Location { parents: 2, interior: Here };
689 assert_eq!(m.prepend_with(prefix.clone()), Err(prefix));
690
691 let prefix = Location { parents: 1, interior: Here };
692 assert_eq!(m.prepend_with(prefix.clone()), Ok(()));
693 assert_eq!(m, Location { parents: 255, interior: [Parachain(42)].into() });
694 }
695
696 #[test]
697 fn double_ended_ref_iteration_works() {
698 let m: Junctions = [Parachain(1000), Parachain(3), PalletInstance(5)].into();
699 let mut iter = m.iter();
700
701 let first = iter.next().unwrap();
702 assert_eq!(first, &Parachain(1000));
703 let third = iter.next_back().unwrap();
704 assert_eq!(third, &PalletInstance(5));
705 let second = iter.next_back().unwrap();
706 assert_eq!(iter.next(), None);
707 assert_eq!(iter.next_back(), None);
708 assert_eq!(second, &Parachain(3));
709
710 let res = Here
711 .pushed_with(*first)
712 .unwrap()
713 .pushed_with(*second)
714 .unwrap()
715 .pushed_with(*third)
716 .unwrap();
717 assert_eq!(m, res);
718
719 let m = Here;
721 let mut iter = m.iter();
722
723 assert_eq!(iter.next(), None);
724 assert_eq!(iter.next_back(), None);
725 }
726
727 #[test]
728 fn conversion_from_other_types_works() {
729 use crate::v4;
730
731 fn takes_location<Arg: Into<Location>>(_arg: Arg) {}
732
733 takes_location(Parent);
734 takes_location(Here);
735 takes_location([Parachain(42)]);
736 takes_location((Ancestor(255), PalletInstance(8)));
737 takes_location((Ancestor(5), Parachain(1), PalletInstance(3)));
738 takes_location((Ancestor(2), Here));
739 takes_location(AncestorThen(
740 3,
741 [Parachain(43), AccountIndex64 { network: None, index: 155 }],
742 ));
743 takes_location((Parent, AccountId32 { network: None, id: [0; 32] }));
744 takes_location((Parent, Here));
745 takes_location(ParentThen([Parachain(75)].into()));
746 takes_location([Parachain(100), PalletInstance(3)]);
747
748 assert_eq!(v4::Location::from(v4::Junctions::Here).try_into(), Ok(Location::here()));
749 assert_eq!(v4::Location::from(v4::Parent).try_into(), Ok(Location::parent()));
750 assert_eq!(
751 v4::Location::from((v4::Parent, v4::Parent, v4::Junction::GeneralIndex(42u128),))
752 .try_into(),
753 Ok(Location { parents: 2, interior: [GeneralIndex(42u128)].into() }),
754 );
755 }
756}