1use crate::models::*;
2use itertools::Itertools;
3use smallvec::SmallVec;
4use std::borrow::Cow;
5use std::fmt::{Display, Formatter};
6use std::hash::{Hash, Hasher};
7use std::iter::FromIterator;
8use std::marker::PhantomData;
9use std::mem::discriminant;
10
11#[derive(Debug, Clone)]
17pub enum AsPathSegment {
18 AsSequence(SmallVec<[Asn; 6]>),
20 AsSet(SmallVec<[Asn; 6]>),
22 ConfedSequence(SmallVec<[Asn; 6]>),
24 ConfedSet(SmallVec<[Asn; 6]>),
26}
27
28impl AsPathSegment {
29 pub fn sequence<S: AsRef<[u32]>>(seq: S) -> Self {
31 AsPathSegment::AsSequence(seq.as_ref().iter().copied().map_into().collect())
32 }
33
34 pub fn set<S: AsRef<[u32]>>(seq: S) -> Self {
36 AsPathSegment::AsSet(seq.as_ref().iter().copied().map_into().collect())
37 }
38
39 pub fn route_len(&self) -> usize {
42 match self {
43 AsPathSegment::AsSequence(v) => v.len(),
44 AsPathSegment::AsSet(_) => 1,
45 AsPathSegment::ConfedSequence(_) | AsPathSegment::ConfedSet(_) => 0,
46 }
47 }
48
49 pub fn len(&self) -> usize {
52 self.as_ref().len()
53 }
54
55 pub fn is_empty(&self) -> bool {
57 self.as_ref().is_empty()
58 }
59
60 pub fn iter(&self) -> <&'_ Self as IntoIterator>::IntoIter {
62 self.into_iter()
63 }
64
65 pub fn iter_mut(&mut self) -> <&'_ mut Self as IntoIterator>::IntoIter {
67 self.into_iter()
68 }
69
70 pub fn is_confed(&self) -> bool {
75 matches!(
76 self,
77 AsPathSegment::ConfedSequence(_) | AsPathSegment::ConfedSet(_)
78 )
79 }
80
81 fn merge_in_place(&mut self, other: &mut Self) -> bool {
85 use AsPathSegment::*;
86
87 match (self, other) {
88 (AsSequence(x), AsSequence(y)) | (ConfedSequence(x), ConfedSequence(y)) => {
89 x.extend_from_slice(y);
90 true
91 }
92 (x @ (AsSequence(_) | ConfedSequence(_)), y) if x.is_empty() => {
93 std::mem::swap(x, y);
94 true
95 }
96 (_, AsSequence(y) | ConfedSequence(y)) if y.is_empty() => true,
97 _ => false,
98 }
99 }
100
101 fn dedup_merge_in_place(&mut self, other: &mut Self) -> bool {
106 use AsPathSegment::*;
107
108 other.dedup();
109 match (self, other) {
110 (AsSequence(x), AsSequence(y)) | (ConfedSequence(x), ConfedSequence(y)) => {
111 x.extend_from_slice(y);
112 x.dedup();
113 true
114 }
115 (x @ (AsSequence(_) | ConfedSequence(_)), y) if x.is_empty() => {
116 std::mem::swap(x, y);
117 true
118 }
119 (_, AsSequence(y) | ConfedSequence(y)) if y.is_empty() => true,
120 _ => false,
121 }
122 }
123
124 fn dedup(&mut self) {
129 match self {
130 AsPathSegment::AsSequence(x) | AsPathSegment::ConfedSequence(x) => x.dedup(),
131 AsPathSegment::AsSet(x) => {
132 x.sort_unstable();
133 x.dedup();
134 if x.len() == 1 {
135 *self = AsPathSegment::AsSequence(std::mem::take(x));
136 }
137 }
138 AsPathSegment::ConfedSet(x) => {
139 x.sort_unstable();
140 x.dedup();
141 if x.len() == 1 {
142 *self = AsPathSegment::ConfedSequence(std::mem::take(x));
143 }
144 }
145 }
146 }
147
148 pub fn to_u32_vec_opt(&self, dedup: bool) -> Option<Vec<u32>> {
149 match self {
150 AsPathSegment::AsSequence(v) => {
151 let mut p: Vec<u32> = v.iter().map(|asn| (*asn).into()).collect();
152 if dedup {
153 p.dedup();
154 }
155 Some(p)
156 }
157 AsPathSegment::AsSet(v) => {
158 if v.len() == 1 {
159 Some(vec![v[0].into()])
162 } else {
163 None
164 }
165 }
166 _ => None,
167 }
168 }
169}
170
171impl IntoIterator for AsPathSegment {
172 type Item = Asn;
173 type IntoIter = smallvec::IntoIter<[Asn; 6]>;
174
175 fn into_iter(self) -> Self::IntoIter {
176 let (AsPathSegment::AsSequence(x)
177 | AsPathSegment::AsSet(x)
178 | AsPathSegment::ConfedSequence(x)
179 | AsPathSegment::ConfedSet(x)) = self;
180 x.into_iter()
181 }
182}
183
184impl<'a> IntoIterator for &'a AsPathSegment {
185 type Item = &'a Asn;
186 type IntoIter = std::slice::Iter<'a, Asn>;
187
188 fn into_iter(self) -> Self::IntoIter {
189 let (AsPathSegment::AsSequence(x)
190 | AsPathSegment::AsSet(x)
191 | AsPathSegment::ConfedSequence(x)
192 | AsPathSegment::ConfedSet(x)) = self;
193 x.iter()
194 }
195}
196
197impl<'a> IntoIterator for &'a mut AsPathSegment {
198 type Item = &'a mut Asn;
199 type IntoIter = std::slice::IterMut<'a, Asn>;
200
201 fn into_iter(self) -> Self::IntoIter {
202 let (AsPathSegment::AsSequence(x)
203 | AsPathSegment::AsSet(x)
204 | AsPathSegment::ConfedSequence(x)
205 | AsPathSegment::ConfedSet(x)) = self;
206 x.iter_mut()
207 }
208}
209
210impl AsRef<[Asn]> for AsPathSegment {
211 fn as_ref(&self) -> &[Asn] {
212 let (AsPathSegment::AsSequence(x)
213 | AsPathSegment::AsSet(x)
214 | AsPathSegment::ConfedSequence(x)
215 | AsPathSegment::ConfedSet(x)) = self;
216 x
217 }
218}
219
220impl Hash for AsPathSegment {
221 fn hash<H: Hasher>(&self, state: &mut H) {
222 discriminant(self).hash(state);
224
225 let set = match self {
226 AsPathSegment::AsSequence(x) | AsPathSegment::ConfedSequence(x) => {
227 return x.hash(state)
228 }
229 AsPathSegment::AsSet(x) | AsPathSegment::ConfedSet(x) => x,
230 };
231
232 if set.len() <= 32 {
234 let mut buffer = [Asn::new_32bit(0); 32];
235 set.iter()
236 .zip(&mut buffer)
237 .for_each(|(asn, buffer)| *buffer = *asn);
238
239 let slice = &mut buffer[..set.len()];
240 slice.sort_unstable();
241 Asn::hash_slice(slice, state);
242 return;
243 }
244
245 set.iter().sorted().for_each(|x| x.hash(state));
247 }
248}
249
250impl PartialEq for AsPathSegment {
265 fn eq(&self, other: &Self) -> bool {
266 let (x, y) = match (self, other) {
267 (AsPathSegment::AsSequence(x), AsPathSegment::AsSequence(y))
268 | (AsPathSegment::ConfedSequence(x), AsPathSegment::ConfedSequence(y)) => {
269 return x == y
270 }
271 (AsPathSegment::AsSet(x), AsPathSegment::AsSet(y))
272 | (AsPathSegment::ConfedSet(x), AsPathSegment::ConfedSet(y)) => (x, y),
273 _ => return false,
274 };
275
276 if x.len() != y.len() {
278 return false;
279 } else if x == y {
280 return true;
281 }
282
283 if x.len() <= 32 {
284 let mut x_buffer = [Asn::new_32bit(0); 32];
285 let mut y_buffer = [Asn::new_32bit(0); 32];
286 x.iter()
287 .zip(&mut x_buffer)
288 .for_each(|(asn, buffer)| *buffer = *asn);
289 y.iter()
290 .zip(&mut y_buffer)
291 .for_each(|(asn, buffer)| *buffer = *asn);
292
293 x_buffer[..x.len()].sort_unstable();
294 y_buffer[..y.len()].sort_unstable();
295 return x_buffer[..x.len()] == y_buffer[..y.len()];
296 }
297
298 x.iter()
299 .sorted()
300 .zip(y.iter().sorted())
301 .all(|(a, b)| a == b)
302 }
303}
304
305impl Eq for AsPathSegment {}
306
307struct AsPathNumberedRouteIter<'a> {
311 path: &'a [AsPathSegment],
312 index: usize,
313 route_num: u64,
314}
315
316impl Iterator for AsPathNumberedRouteIter<'_> {
317 type Item = Asn;
318
319 fn next(&mut self) -> Option<Self::Item> {
320 loop {
321 match self.path.first()? {
322 AsPathSegment::AsSequence(x) => match x.get(self.index) {
323 None => {
324 self.index = 0;
325 self.path = &self.path[1..];
326 }
327 Some(asn) => {
328 self.index += 1;
329 return Some(*asn);
330 }
331 },
332 AsPathSegment::AsSet(x) => {
333 self.path = &self.path[1..];
334 if x.is_empty() {
335 return Some(Asn::RESERVED);
336 }
337
338 let asn = x[(self.route_num % x.len() as u64) as usize];
339 self.route_num /= x.len() as u64;
340 return Some(asn);
341 }
342 _ => self.path = &self.path[1..],
343 }
344 }
345 }
346}
347
348pub struct AsPathRouteIter<'a, D> {
349 path: Cow<'a, [AsPathSegment]>,
350 route_num: u64,
351 total_routes: u64,
352 _phantom: PhantomData<D>,
353}
354
355impl<D> Iterator for AsPathRouteIter<'_, D>
356where
357 D: FromIterator<Asn>,
358{
359 type Item = D;
360
361 fn next(&mut self) -> Option<Self::Item> {
362 if self.route_num >= self.total_routes {
363 return None;
364 }
365
366 if self.route_num == 0 && self.path.len() == 1 {
368 if let AsPathSegment::AsSequence(sequence) = &self.path[0] {
369 let route = D::from_iter(sequence.iter().copied());
370 self.route_num += 1;
371 return Some(route);
372 }
373 }
374
375 let route_asn_iter = AsPathNumberedRouteIter {
376 path: self.path.as_ref(),
377 index: 0,
378 route_num: self.route_num,
379 };
380
381 self.route_num += 1;
382 Some(D::from_iter(route_asn_iter))
383 }
384}
385
386#[derive(Debug, PartialEq, Clone, Eq, Default, Hash)]
391pub struct AsPath {
392 pub segments: SmallVec<[AsPathSegment; 1]>,
394}
395
396#[cfg(feature = "ts-rs")]
402#[derive(ts_rs::TS)]
403#[ts(
404 export,
405 type = "(number | number[] | { ty: \"AS_SET\" | \"AS_SEQUENCE\" | \"AS_CONFED_SEQUENCE\" | \"AS_CONFED_SET\", values: number[] })[]"
406)]
407pub struct AsPathWire;
408
409pub type SegmentIter<'a> = std::slice::Iter<'a, AsPathSegment>;
412pub type SegmentIterMut<'a> = std::slice::IterMut<'a, AsPathSegment>;
413pub type SegmentIntoIter = smallvec::IntoIter<[AsPathSegment; 1]>;
414
415impl AsPath {
416 pub fn new() -> AsPath {
417 AsPath {
418 segments: SmallVec::new(),
419 }
420 }
421
422 pub fn from_sequence<S: AsRef<[u32]>>(seq: S) -> Self {
424 let segment = AsPathSegment::AsSequence(seq.as_ref().iter().copied().map_into().collect());
425
426 AsPath {
427 segments: SmallVec::from_buf([segment]),
428 }
429 }
430
431 pub fn from_segments<S: Into<SmallVec<[AsPathSegment; 1]>>>(segments: S) -> AsPath {
432 AsPath {
433 segments: segments.into(),
434 }
435 }
436
437 pub fn append_segment(&mut self, segment: AsPathSegment) {
440 self.segments.push(segment);
441 }
442
443 pub fn is_empty(&self) -> bool {
446 self.segments.is_empty()
447 }
448
449 pub fn route_len(&self) -> usize {
456 self.segments.iter().map(AsPathSegment::route_len).sum()
457 }
458
459 pub fn len(&self) -> usize {
462 self.segments.len()
463 }
464
465 pub fn num_route_variations(&self) -> u64 {
468 let mut variations: u64 = 1;
469
470 for segment in &self.segments {
471 if let AsPathSegment::AsSet(x) = segment {
472 variations *= x.len() as u64;
473 }
474 }
475
476 variations
477 }
478
479 pub fn contains_asn(&self, x: Asn) -> bool {
481 self.iter_segments().flatten().contains(&x)
482 }
483
484 pub fn coalesce(&mut self) {
516 let mut end_index = 0;
517 let mut scan_index = 1;
518
519 while scan_index < self.segments.len() {
520 let (a, b) = self.segments.split_at_mut(scan_index);
521 if !AsPathSegment::merge_in_place(&mut a[end_index], &mut b[0]) {
522 end_index += 1;
523 self.segments.swap(end_index, scan_index);
524 }
525 scan_index += 1;
526 }
527
528 self.segments.truncate(end_index + 1);
529 }
530
531 pub fn dedup_coalesce(&mut self) {
564 if !self.segments.is_empty() {
565 self.segments[0].dedup();
566 }
567 let mut end_index = 0;
568 let mut scan_index = 1;
569
570 while scan_index < self.segments.len() {
571 let (a, b) = self.segments.split_at_mut(scan_index);
572 if !AsPathSegment::dedup_merge_in_place(&mut a[end_index], &mut b[0]) {
573 end_index += 1;
574 self.segments.swap(end_index, scan_index);
575 }
576 scan_index += 1;
577 }
578
579 self.segments.truncate(end_index + 1);
580 }
581
582 pub fn has_equivalent_routing(&self, other: &Self) -> bool {
587 let mut a = self.to_owned();
588 let mut b = other.to_owned();
589
590 a.dedup_coalesce();
591 b.dedup_coalesce();
592
593 a == b
594 }
595
596 pub fn required_asn_length(&self) -> AsnLength {
598 self.iter_segments().flatten().map(Asn::required_len).fold(
599 AsnLength::Bits16,
600 |a, b| match (a, b) {
601 (AsnLength::Bits16, AsnLength::Bits16) => AsnLength::Bits16,
602 _ => AsnLength::Bits32,
603 },
604 )
605 }
606
607 pub fn iter_segments(&self) -> SegmentIter<'_> {
608 self.segments.iter()
609 }
610
611 pub fn iter_segments_mut(&mut self) -> SegmentIterMut<'_> {
612 self.segments.iter_mut()
613 }
614
615 pub fn into_segments_iter(self) -> SegmentIntoIter {
616 self.segments.into_iter()
617 }
618
619 pub fn iter_routes<D>(&self) -> AsPathRouteIter<'_, D>
621 where
622 D: FromIterator<Asn>,
623 {
624 AsPathRouteIter {
625 path: Cow::Borrowed(&self.segments),
626 route_num: 0,
627 total_routes: self.num_route_variations(),
628 _phantom: PhantomData,
629 }
630 }
631
632 pub fn merge_aspath_as4path(aspath: &AsPath, as4path: &AsPath) -> AsPath {
654 if aspath.route_len() < as4path.route_len() {
655 return aspath.clone();
657 }
658
659 let mut leading = aspath.route_len() - as4path.route_len();
665 let mut new_segs: Vec<AsPathSegment> = vec![];
666 for seg in &aspath.segments {
667 if leading == 0 {
668 break;
669 }
670 match seg.route_len() {
671 0 => new_segs.push(seg.clone()),
675 n if n <= leading => {
676 new_segs.push(seg.clone());
677 leading -= n;
678 }
679 _ => {
680 let AsPathSegment::AsSequence(v) = seg else {
684 unreachable!("only an AS_SEQUENCE can exceed the leading count");
685 };
686 new_segs.push(AsPathSegment::AsSequence(
687 v.iter().take(leading).copied().collect(),
688 ));
689 leading = 0;
690 }
691 }
692 }
693 new_segs.extend(as4path.segments.iter().cloned());
694
695 let mut merged = AsPath {
696 segments: new_segs.into(),
697 };
698 merged.coalesce();
699 merged
700 }
701
702 pub fn iter_origins(&self) -> impl '_ + Iterator<Item = Asn> {
705 let origin_slice = match self.segments.last() {
706 Some(AsPathSegment::AsSequence(v)) => v.last().map(std::slice::from_ref).unwrap_or(&[]),
707 Some(AsPathSegment::AsSet(v)) => v.as_ref(),
708 _ => &[],
709 };
710
711 origin_slice.iter().copied()
712 }
713
714 pub fn get_origin_opt(&self) -> Option<Asn> {
718 match self.segments.last() {
719 Some(AsPathSegment::AsSequence(v)) => v.last().copied(),
720 Some(AsPathSegment::AsSet(v)) if v.len() == 1 => Some(v[0]),
721 _ => None,
722 }
723 }
724
725 pub fn get_collector_opt(&self) -> Option<Asn> {
728 match self.segments.first() {
729 Some(AsPathSegment::AsSequence(v)) => v.first().copied(),
730 Some(AsPathSegment::AsSet(v)) if v.len() == 1 => Some(v[0]),
731 _ => None,
732 }
733 }
734
735 pub fn to_u32_vec_opt(&self, dedup: bool) -> Option<Vec<u32>> {
736 let mut path = vec![];
737
738 for seg in self.segments.iter().rev() {
740 let p = seg.to_u32_vec_opt(dedup)?;
743 path.extend(p.iter().rev());
745 }
746
747 match path.is_empty() {
748 true => {
749 None
751 }
752 false => {
753 path.reverse();
755 Some(path)
756 }
757 }
758 }
759}
760
761impl<'a> IntoIterator for &'a AsPath {
763 type Item = Vec<Asn>;
764 type IntoIter = AsPathRouteIter<'a, Vec<Asn>>;
765
766 fn into_iter(self) -> Self::IntoIter {
767 self.iter_routes()
768 }
769}
770
771impl IntoIterator for AsPath {
773 type Item = Vec<Asn>;
774 type IntoIter = AsPathRouteIter<'static, Vec<Asn>>;
775
776 fn into_iter(self) -> Self::IntoIter {
777 AsPathRouteIter {
778 total_routes: self.num_route_variations(),
779 path: Cow::Owned(self.segments.into_vec()),
780 route_num: 0,
781 _phantom: PhantomData,
782 }
783 }
784}
785
786impl Display for AsPath {
787 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
788 for (index, segment) in self.iter_segments().enumerate() {
789 if index != 0 {
790 write!(f, " ")?;
791 }
792
793 match segment {
794 AsPathSegment::AsSequence(v) | AsPathSegment::ConfedSequence(v) => {
795 let mut asn_iter = v.iter();
796 if let Some(first_element) = asn_iter.next() {
797 write!(f, "{first_element}")?;
798
799 for asn in asn_iter {
800 write!(f, " {asn}")?;
801 }
802 }
803 }
804 AsPathSegment::AsSet(v) | AsPathSegment::ConfedSet(v) => {
805 write!(f, "{{")?;
806 let mut asn_iter = v.iter();
807 if let Some(first_element) = asn_iter.next() {
808 write!(f, "{first_element}")?;
809
810 for asn in asn_iter {
811 write!(f, ",{asn}")?;
812 }
813 }
814 write!(f, "}}")?;
815 }
816 }
817 }
818
819 Ok(())
820 }
821}
822
823#[cfg(feature = "serde")]
824mod serde_impl {
825 use super::*;
826 use serde::de::{SeqAccess, Visitor};
827 use serde::ser::SerializeSeq;
828 use serde::{Deserialize, Deserializer, Serialize, Serializer};
829 use std::borrow::Cow;
830
831 #[allow(non_camel_case_types)]
835 #[derive(Serialize, Deserialize)]
836 enum SegmentType {
837 AS_SET,
838 AS_SEQUENCE,
839 AS_CONFED_SEQUENCE,
840 AS_CONFED_SET,
841 }
842
843 #[derive(Serialize, Deserialize)]
844 struct VerboseSegment<'s> {
845 ty: SegmentType,
846 values: Cow<'s, [Asn]>,
847 }
848
849 impl Serialize for AsPathSegment {
850 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
851 where
852 S: Serializer,
853 {
854 let (ty, elements) = match self {
855 AsPathSegment::AsSequence(x) => (SegmentType::AS_SEQUENCE, x.as_ref()),
856 AsPathSegment::AsSet(x) => (SegmentType::AS_SET, x.as_ref()),
857 AsPathSegment::ConfedSequence(x) => (SegmentType::AS_CONFED_SEQUENCE, x.as_ref()),
858 AsPathSegment::ConfedSet(x) => (SegmentType::AS_CONFED_SET, x.as_ref()),
859 };
860
861 let verbose = VerboseSegment {
862 ty,
863 values: Cow::Borrowed(elements),
864 };
865
866 verbose.serialize(serializer)
867 }
868 }
869
870 impl<'de> Deserialize<'de> for AsPathSegment {
871 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
872 where
873 D: Deserializer<'de>,
874 {
875 let verbose = VerboseSegment::deserialize(deserializer)?;
876
877 let values: SmallVec<[Asn; 6]> = verbose.values.into_owned().into();
878 match verbose.ty {
879 SegmentType::AS_SET => Ok(AsPathSegment::AsSet(values)),
880 SegmentType::AS_SEQUENCE => Ok(AsPathSegment::AsSequence(values)),
881 SegmentType::AS_CONFED_SEQUENCE => Ok(AsPathSegment::ConfedSequence(values)),
882 SegmentType::AS_CONFED_SET => Ok(AsPathSegment::ConfedSet(values)),
883 }
884 }
885 }
886
887 fn simplified_format_len(segments: &[AsPathSegment]) -> Option<usize> {
891 let mut elements = 0;
892 let mut prev_was_sequence = false;
893 for segment in segments {
894 match segment {
895 AsPathSegment::AsSequence(seq) if !prev_was_sequence => {
896 prev_was_sequence = true;
897 elements += seq.len();
898 }
899 AsPathSegment::AsSet(_) => {
900 prev_was_sequence = false;
901 elements += 1;
902 }
903 _ => return None,
904 }
905 }
906
907 Some(elements)
908 }
909
910 impl Serialize for AsPath {
959 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
960 where
961 S: Serializer,
962 {
963 if let Some(num_elements) = simplified_format_len(&self.segments) {
964 let mut seq_serializer = serializer.serialize_seq(Some(num_elements))?;
966
967 for segment in &self.segments {
968 match segment {
969 AsPathSegment::AsSequence(elements) => {
970 elements
971 .iter()
972 .try_for_each(|x| seq_serializer.serialize_element(x))?;
973 }
974 AsPathSegment::AsSet(x) => seq_serializer.serialize_element(x)?,
975 _ => unreachable!("simplified_format_len checked for confed segments"),
976 }
977 }
978 return seq_serializer.end();
979 }
980
981 serializer.collect_seq(&self.segments)
983 }
984 }
985
986 struct AsPathVisitor;
987
988 impl<'de> Visitor<'de> for AsPathVisitor {
989 type Value = AsPath;
990
991 fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
992 formatter.write_str("list of AS_PATH segments")
993 }
994
995 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
996 where
997 A: SeqAccess<'de>,
998 {
999 #[derive(Deserialize)]
1002 #[serde(untagged)]
1003 enum PathElement {
1004 SequenceElement(Asn),
1005 Set(Vec<Asn>),
1006 Verbose(AsPathSegment),
1007 }
1008
1009 let mut append_new_sequence = false;
1010 let mut segments: SmallVec<[AsPathSegment; 1]> = SmallVec::new();
1011 while let Some(element) = seq.next_element()? {
1012 match element {
1013 PathElement::SequenceElement(x) => {
1014 if append_new_sequence {
1015 append_new_sequence = false;
1018 segments.push(AsPathSegment::AsSequence(SmallVec::new()));
1019 }
1020
1021 if let Some(AsPathSegment::AsSequence(last_sequence)) = segments.last_mut()
1022 {
1023 last_sequence.push(x);
1024 } else {
1025 let mut new_seq: SmallVec<[Asn; 6]> = SmallVec::new();
1026 new_seq.push(x);
1027 segments.push(AsPathSegment::AsSequence(new_seq));
1028 }
1029 }
1030 PathElement::Set(values) => {
1031 segments.push(AsPathSegment::AsSet(values.into()));
1032 }
1033 PathElement::Verbose(verbose) => {
1034 segments.push(verbose);
1035 }
1036 }
1037 }
1038
1039 Ok(AsPath { segments })
1040 }
1041 }
1042
1043 impl<'de> Deserialize<'de> for AsPath {
1044 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1045 where
1046 D: Deserializer<'de>,
1047 {
1048 deserializer.deserialize_seq(AsPathVisitor)
1049 }
1050 }
1051}
1052
1053#[cfg(test)]
1054mod tests {
1055 use crate::models::*;
1056 use itertools::Itertools;
1057 use std::collections::HashSet;
1058
1059 #[test]
1060 fn test_aspath_as4path_merge() {
1061 let aspath = AsPath::from_sequence([1, 2, 3, 5]);
1062 let as4path = AsPath::from_sequence([2, 3, 7]);
1063 let newpath = AsPath::merge_aspath_as4path(&aspath, &as4path);
1064 assert_eq!(newpath.segments[0], AsPathSegment::sequence([1, 2, 3, 7]));
1065
1066 let aspath = AsPath::from_sequence([1, 2]);
1067 let as4path = AsPath::from_sequence([2, 3, 7]);
1068 let newpath = AsPath::merge_aspath_as4path(&aspath, &as4path);
1069 assert_eq!(newpath.segments[0], AsPathSegment::sequence([1, 2]));
1070
1071 let aspath = AsPath::from_sequence([1, 2]);
1073 let as4path = AsPath::from_sequence([3, 4]);
1074 let newpath = AsPath::merge_aspath_as4path(&aspath, &as4path);
1075 assert_eq!(newpath.segments[0], AsPathSegment::sequence([3, 4]));
1076
1077 let aspath = AsPath::from_segments(vec![
1078 AsPathSegment::sequence([1, 2, 3, 5]),
1079 AsPathSegment::set([7, 8]),
1080 ]);
1081 let as4path = AsPath::from_sequence([6, 7, 8]);
1082 let newpath = AsPath::merge_aspath_as4path(&aspath, &as4path);
1083 assert_eq!(newpath.segments.len(), 1);
1086 assert_eq!(
1087 newpath.segments[0],
1088 AsPathSegment::sequence([1, 2, 6, 7, 8])
1089 );
1090
1091 let aspath = AsPath::from_segments(vec![
1092 AsPathSegment::sequence([1, 2]),
1093 AsPathSegment::sequence([3, 5]),
1094 AsPathSegment::set([13, 14]),
1095 ]);
1096 let as4path = AsPath::from_segments(vec![
1097 AsPathSegment::sequence([8, 4, 6]),
1098 AsPathSegment::set([11, 12]),
1099 ]);
1100 let newpath = AsPath::merge_aspath_as4path(&aspath, &as4path);
1101 assert_eq!(newpath.segments.len(), 2);
1103 assert_eq!(newpath.segments[0], AsPathSegment::sequence([1, 8, 4, 6]));
1104 assert_eq!(newpath.segments[1], AsPathSegment::set([11, 12]));
1105
1106 let aspath = AsPath::from_segments(vec![
1107 AsPathSegment::sequence([1, 2, 3]),
1108 AsPathSegment::sequence([5]),
1109 AsPathSegment::set([13, 14]),
1110 ]);
1111 let as4path = AsPath::from_segments(vec![
1112 AsPathSegment::sequence([7, 8]),
1113 AsPathSegment::set([11, 12]),
1114 ]);
1115 let newpath = AsPath::merge_aspath_as4path(&aspath, &as4path);
1116 assert_eq!(newpath.segments.len(), 2);
1118 assert_eq!(newpath.segments[0], AsPathSegment::sequence([1, 2, 7, 8]));
1119 assert_eq!(newpath.segments[1], AsPathSegment::set([11, 12]));
1120
1121 let aspath = AsPath::from_segments(vec![
1124 AsPathSegment::sequence([1, 2]),
1125 AsPathSegment::sequence([3, 4]),
1126 ]);
1127 let as4path = AsPath::from_sequence([9, 10]);
1128 let newpath = AsPath::merge_aspath_as4path(&aspath, &as4path);
1129 assert_eq!(newpath.segments.len(), 1);
1130 assert_eq!(newpath.segments[0], AsPathSegment::sequence([1, 2, 9, 10]));
1131 }
1132
1133 #[test]
1134 fn test_get_origin() {
1135 let aspath = AsPath::from_sequence([1, 2, 3, 5]);
1136 let origin = aspath.get_origin_opt();
1137 assert_eq!(origin.unwrap(), 5);
1138
1139 let aspath = AsPath::from_segments(vec![AsPathSegment::set([1, 2, 3, 5])]);
1140 let origin = aspath.get_origin_opt();
1141 assert!(origin.is_none());
1142
1143 let aspath = AsPath::from_segments(vec![AsPathSegment::set([1])]);
1144 let origin = aspath.get_origin_opt();
1145 assert_eq!(origin.unwrap(), 1);
1146
1147 let aspath = AsPath::from_segments(vec![
1148 AsPathSegment::sequence([1, 2, 3, 5]),
1149 AsPathSegment::set([7, 8]),
1150 ]);
1151 let origins = aspath.iter_origins().map_into::<u32>().collect::<Vec<_>>();
1152 assert_eq!(origins, vec![7, 8]);
1153
1154 let aspath = AsPath::from_segments(vec![
1155 AsPathSegment::sequence([1, 2, 3, 5]),
1156 AsPathSegment::ConfedSet(vec![Asn::new_32bit(9)].into()),
1157 ]);
1158 let origins = aspath.iter_origins().map_into::<u32>().collect::<Vec<_>>();
1159 assert_eq!(origins, Vec::<u32>::new());
1160 }
1161
1162 #[test]
1163 fn test_get_collector() {
1164 let aspath = AsPath::from_sequence([1, 2, 3, 5]);
1165 let collector = aspath.get_collector_opt();
1166 assert_eq!(collector.unwrap(), 1);
1167
1168 let aspath = AsPath::from_segments(vec![AsPathSegment::set([7])]);
1169 let collector = aspath.get_collector_opt();
1170 assert_eq!(collector.unwrap(), 7);
1171
1172 let aspath = AsPath::from_segments(vec![AsPathSegment::set([7, 8])]);
1173 let collector = aspath.get_collector_opt();
1174 assert!(collector.is_none());
1175 }
1176
1177 #[test]
1178 fn test_aspath_route_iter() {
1179 let path = AsPath::from_segments(vec![AsPathSegment::sequence([3, 4])]);
1180 let mut routes = HashSet::new();
1181 for route in &path {
1182 assert!(routes.insert(route));
1183 }
1184 assert_eq!(1, routes.len());
1185
1186 let path = AsPath::from_segments(vec![
1187 AsPathSegment::set([3, 4]),
1188 AsPathSegment::set([5, 6]),
1189 AsPathSegment::sequence([7, 8]),
1190 AsPathSegment::ConfedSet(vec![Asn::new_32bit(9)].into()),
1191 AsPathSegment::ConfedSequence(vec![Asn::new_32bit(9)].into()),
1192 ]);
1193 assert_eq!(path.route_len(), 4);
1194
1195 let mut routes = HashSet::new();
1196 for route in &path {
1197 assert!(routes.insert(route));
1198 }
1199
1200 assert_eq!(routes.len(), 4);
1201 assert!(routes.contains(&vec![
1202 Asn::from(3),
1203 Asn::from(5),
1204 Asn::from(7),
1205 Asn::from(8)
1206 ]));
1207 assert!(routes.contains(&vec![
1208 Asn::from(3),
1209 Asn::from(6),
1210 Asn::from(7),
1211 Asn::from(8)
1212 ]));
1213 assert!(routes.contains(&vec![
1214 Asn::from(4),
1215 Asn::from(5),
1216 Asn::from(7),
1217 Asn::from(8)
1218 ]));
1219 assert!(routes.contains(&vec![
1220 Asn::from(4),
1221 Asn::from(6),
1222 Asn::from(7),
1223 Asn::from(8)
1224 ]));
1225 }
1226
1227 #[test]
1228 fn test_segment() {
1229 let path_segment = AsPathSegment::sequence([1, 2, 3, 4]);
1230 assert_eq!(path_segment.len(), 4);
1231
1232 let mut iter = path_segment.iter();
1234 assert_eq!(iter.next(), Some(&Asn::new_32bit(1)));
1235 assert_eq!(iter.next(), Some(&Asn::new_32bit(2)));
1236 assert_eq!(iter.next(), Some(&Asn::new_32bit(3)));
1237 assert_eq!(iter.next(), Some(&Asn::new_32bit(4)));
1238 assert_eq!(iter.next(), None);
1239
1240 let mut path_segment = AsPathSegment::sequence([1]);
1242 let mut iter_mut = path_segment.iter_mut();
1243 assert_eq!(iter_mut.next(), Some(&mut Asn::new_32bit(1)));
1244 assert_eq!(iter_mut.next(), None);
1245
1246 assert!(AsPathSegment::ConfedSequence(vec![Asn::new_32bit(1)].into()).is_confed());
1248 assert!(AsPathSegment::ConfedSet(vec![Asn::new_32bit(1)].into()).is_confed());
1249 }
1250
1251 #[test]
1252 fn test_coalesce() {
1253 let mut a = AsPath::from_segments(vec![
1254 AsPathSegment::sequence([]),
1255 AsPathSegment::sequence([1, 2]),
1256 AsPathSegment::sequence([]),
1257 AsPathSegment::sequence([2]),
1258 AsPathSegment::set([2]),
1259 AsPathSegment::set([5, 3, 3, 2]),
1260 ]);
1261
1262 let expected = AsPath::from_segments(vec![
1263 AsPathSegment::sequence([1, 2, 2]),
1264 AsPathSegment::set([2]),
1265 AsPathSegment::set([5, 3, 3, 2]),
1266 ]);
1267
1268 a.coalesce();
1269 assert_eq!(a, expected);
1270 }
1271
1272 #[test]
1273 fn test_confed_set_dedup() {
1274 let mut path_segment =
1275 AsPathSegment::ConfedSet(vec![Asn::new_32bit(1), Asn::new_32bit(1)].into());
1276 path_segment.dedup();
1277 assert_eq!(
1278 path_segment,
1279 AsPathSegment::ConfedSequence(vec![Asn::new_32bit(1)].into())
1280 );
1281
1282 let mut path_segment = AsPathSegment::ConfedSet(
1283 vec![Asn::new_32bit(1), Asn::new_32bit(2), Asn::new_32bit(2)].into(),
1284 );
1285 path_segment.dedup();
1286 assert_eq!(
1287 path_segment,
1288 AsPathSegment::ConfedSet(vec![Asn::new_32bit(1), Asn::new_32bit(2)].into())
1289 );
1290 }
1291
1292 #[test]
1293 fn test_path_to_u32() {
1294 let path_segment = AsPathSegment::sequence([1, 2, 3, 3]);
1296 assert_eq!(path_segment.to_u32_vec_opt(false), Some(vec![1, 2, 3, 3]));
1297 assert_eq!(path_segment.to_u32_vec_opt(true), Some(vec![1, 2, 3]));
1298
1299 let path_segment = AsPathSegment::set([1, 2, 3, 3]);
1301 assert_eq!(path_segment.to_u32_vec_opt(false), None);
1302 assert_eq!(path_segment.to_u32_vec_opt(true), None);
1303
1304 let path_segment = AsPathSegment::set([1]);
1306 assert_eq!(path_segment.to_u32_vec_opt(false), Some(vec![1]));
1307 assert_eq!(path_segment.to_u32_vec_opt(true), Some(vec![1]));
1308
1309 let as_path = AsPath::from_segments(vec![
1311 AsPathSegment::set([4]),
1312 AsPathSegment::sequence([2, 3, 3]),
1313 AsPathSegment::set([1]),
1314 ]);
1315 assert_eq!(as_path.to_u32_vec_opt(false), Some(vec![4, 2, 3, 3, 1]));
1316 assert_eq!(as_path.to_u32_vec_opt(true), Some(vec![4, 2, 3, 1]));
1317
1318 let as_path = AsPath::from_segments(vec![
1320 AsPathSegment::set([4, 2]),
1321 AsPathSegment::sequence([2, 3, 3]),
1322 AsPathSegment::set([1]),
1323 ]);
1324 assert_eq!(as_path.to_u32_vec_opt(false), None);
1325 assert_eq!(as_path.to_u32_vec_opt(true), None);
1326
1327 let as_path = AsPath::from_segments(vec![]);
1331 assert_eq!(as_path.to_u32_vec_opt(false), None);
1332 assert_eq!(as_path.to_u32_vec_opt(true), None);
1333
1334 let as_path = AsPath::from_segments(vec![
1336 AsPathSegment::ConfedSet(vec![Asn::new_32bit(1), Asn::new_32bit(2)].into()),
1337 AsPathSegment::ConfedSequence(vec![Asn::new_32bit(3), Asn::new_32bit(4)].into()),
1338 ]);
1339 assert_eq!(as_path.to_u32_vec_opt(false), None);
1340 assert_eq!(as_path.to_u32_vec_opt(true), None);
1341 }
1342
1343 #[test]
1344 fn test_as_ref() {
1345 let path_segment = AsPathSegment::sequence([1, 2]);
1346 assert_eq!(
1347 path_segment.as_ref(),
1348 &[Asn::new_32bit(1), Asn::new_32bit(2)]
1349 );
1350
1351 let path_segment = AsPathSegment::set([1, 2]);
1352 assert_eq!(
1353 path_segment.as_ref(),
1354 &[Asn::new_32bit(1), Asn::new_32bit(2)]
1355 );
1356
1357 let path_segment =
1358 AsPathSegment::ConfedSequence(vec![Asn::new_32bit(1), Asn::new_32bit(2)].into());
1359 assert_eq!(
1360 path_segment.as_ref(),
1361 &[Asn::new_32bit(1), Asn::new_32bit(2)]
1362 );
1363
1364 let path_segment =
1365 AsPathSegment::ConfedSet(vec![Asn::new_32bit(1), Asn::new_32bit(2)].into());
1366 assert_eq!(
1367 path_segment.as_ref(),
1368 &[Asn::new_32bit(1), Asn::new_32bit(2)]
1369 );
1370 }
1371
1372 #[test]
1373 fn test_hashing() {
1374 let path_segment = AsPathSegment::sequence([1, 2]);
1375 let path_segment2 = AsPathSegment::sequence([1, 2]);
1376
1377 let hashset = std::iter::once(path_segment).collect::<HashSet<_>>();
1378 assert!(hashset.contains(&path_segment2));
1379 }
1380
1381 #[test]
1382 fn test_equality() {
1383 let path_segment = AsPathSegment::sequence([1, 2]);
1384 let path_segment2 = AsPathSegment::sequence([1, 2]);
1385
1386 assert_eq!(path_segment, path_segment2);
1387
1388 let path_segment = AsPathSegment::sequence([1, 2]);
1389 let path_segment2 = AsPathSegment::set([1, 2, 3]);
1390 assert_ne!(path_segment, path_segment2);
1391
1392 let path_segment = AsPathSegment::sequence((1..33).collect::<Vec<_>>());
1394 let path_segment2 = AsPathSegment::sequence((1..33).collect::<Vec<_>>());
1395 assert_eq!(path_segment, path_segment2);
1396 }
1397
1398 #[test]
1399 fn test_as_path_display() {
1400 let path = AsPath::from_segments(vec![
1401 AsPathSegment::sequence([1, 2]),
1402 AsPathSegment::set([3, 4]),
1403 AsPathSegment::sequence([5, 6]),
1404 AsPathSegment::ConfedSet(vec![Asn::new_32bit(7)].into()),
1405 AsPathSegment::ConfedSequence(vec![Asn::new_32bit(8)].into()),
1406 ]);
1407
1408 assert_eq!(path.to_string(), "1 2 {3,4} 5 6 {7} 8");
1409 }
1410}