@@ -492,61 +492,55 @@ impl fmt::Display for DecisionErrorType {
492
492
493
493
//------------ Helpers -------------------------------------------------------
494
494
495
- pub fn preferred < ' a , OS : OrdStrat > (
496
- a : OrdRoute < ' a , OS > , b : OrdRoute < ' a , OS >
497
- ) -> OrdRoute < ' a , OS > {
495
+
496
+ /// Returns the preferred route.
497
+ ///
498
+ /// Note this method works on anything `T: Ord` and is thus not limited to
499
+ /// `OrdRoute`. Hence one can pass in a tuple of `(OrdRoute, L)` as long as
500
+ /// `L` implements `Ord`, to include and get back any local value like an ID.
501
+ /// This is consistent with [`fn best`] and [`fn best_backup_generic`].
502
+ pub fn preferred < T : Ord > ( a : T , b : T ) -> T {
498
503
cmp:: min ( a, b)
499
504
}
500
505
501
506
/// Selects the preferred ('best') route.
502
- pub fn best < ' a , T , I , OS > ( it : I ) -> Option < T >
507
+ ///
508
+ /// Note this method works on an iterator yielding anything `T: Ord`, so not
509
+ /// limited to `OrdRoute`. It is in that sense consistent with [`fn
510
+ /// best_backup_generic`], i.e. one can pass in tuples of `OrdRoute` and
511
+ /// something else that implements `Ord`.
512
+ pub fn best < T , I > ( it : I ) -> Option < T >
503
513
where
504
514
T : Ord ,
505
515
I : Iterator < Item = T > ,
506
- T : core:: borrow:: Borrow < OrdRoute < ' a , OS > >
507
516
{
508
517
it. min ( )
509
518
}
510
519
511
- /*
512
- pub fn best_with_strat<'a, OS, AltOS, I, T1>(it: I)
513
- -> Option<OrdRoute<'a, AltOS>>
514
- where
515
- OS: 'a + OrdStrat,
516
- AltOS: 'a + OrdStrat,
517
- I: Iterator<Item = T1>,
518
- T1: core::borrow::Borrow<OrdRoute<'a, OS>>
519
- {
520
- it.map(|r| r.into_strat()).min()
521
- }
522
- */
523
-
524
-
525
- // XXX would this be convenient?
526
- pub fn best_alt < ' a , OS : OrdStrat > (
527
- _pamaps : impl Iterator < Item = & ' a PaMap > ,
528
- _tiebreakers : impl Iterator < Item = TiebreakerInfo >
529
- ) -> Option < OrdRoute < ' a , OS > > {
530
- unimplemented ! ( )
531
- }
532
-
533
- /// Returns the 'best' and second-best path.
520
+ /// Alternative, generic version of `fn best_backup`.
534
521
///
535
- /// If the iterator passed in contains no paths, `(None, None)` is returned.
536
- /// If the iterator yields only a single item, that will be the 'best' path,
537
- /// and the 'backup' will be None, i.e. `(Some(best), None)`.
522
+ /// This method takes any iterator yielding items implementing Ord. As such,
523
+ /// it has little to do with routes or path selection per se.
538
524
///
539
- /// In all other cases (an iterator yielding two or more non-identical
540
- /// values), both members of the tuple should be `Some(..)`.
541
- ///
542
- /// The returned 'best' path is the same as the path returned by [`fn best`].
543
- pub fn best_backup < ' a , OS , T > (
544
- it : impl Iterator < Item = T >
545
- ) -> ( Option < T > , Option < T > )
546
- where
547
- OS : OrdStrat ,
548
- T : Ord ,
549
- T : core:: borrow:: Borrow < OrdRoute < ' a , OS > >
525
+ /// Note that because of this genericness, we have no access to methods or
526
+ /// members of `T`, and thus are unable to compare actual contents such as a
527
+ /// `PaMap` or the `TiebreakerInfo` when comparing `OrdRoute`s. This means the
528
+ /// method can not check for any duplicate route information between `T`s, and
529
+ /// really only order them. The caller therefore has to make sure to pass in
530
+ /// an iterator that does not yield any duplicate routes.
531
+ ///
532
+ /// This method enables the caller to attach additional information, as long
533
+ /// as it implements `Ord`. For example, one can pass in an iterator over
534
+ /// tuples of `OrdRoute` and something else. As long as the `OrdRoute` is the
535
+ /// first member of that tuple and no duplicates are yielded from the
536
+ /// iterator, the additional information is not used in the ordering process
537
+ /// but is returned together with the 'best' and 'backup' tuples. This can be
538
+ /// useful when the caller needs to relate routes to local IDs or something
539
+ /// alike.
540
+ pub fn best_backup_generic < I , T > ( it : I ) -> ( Option < T > , Option < T > )
541
+ where
542
+ I : Iterator < Item = T > ,
543
+ T : Ord
550
544
{
551
545
let mut best = None ;
552
546
let mut backup = None ;
@@ -566,33 +560,11 @@ pub fn best_backup<'a, OS, T>(
566
560
567
561
// c is not better than best, now check backup
568
562
match backup. take ( ) {
569
- None => {
570
- // Before we set the backup route, ensure it is not
571
- // the same route as best.
572
- // We compare the actual contents of the OrdRoute
573
- // here, i.e. the TiebreakerInfo and PaMap. If we'd
574
- // simply compare the OrdRoutes themselves, we'd be
575
- // testing whether or not they are considered equal in
576
- // terms of path preference, NOT in terms of content.
577
- // If for example we have a candidate backup path with
578
- // a different AS_PATH but of equal length as the best
579
- // path, the OrdRoutes are considered equal even
580
- // though the actual path attributes differ.
581
- //
582
-
583
- // Best is always Some at this point, unwrap is safe.
584
- if best. as_ref ( ) . unwrap ( ) . borrow ( ) . inner ( ) != c. borrow ( ) . inner ( ) {
585
- backup = Some ( c) ;
586
- } }
563
+ None => { backup = Some ( c) ; }
587
564
Some ( cur_backup) => {
588
565
if c < cur_backup {
589
566
// c is preferred over current backup
590
- // check if it is not the same route as 'best'
591
- if best. as_ref ( ) != Some ( & c) {
592
- backup = Some ( c) ;
593
- } else {
594
- backup = Some ( cur_backup) ;
595
- }
567
+ backup = Some ( c) ;
596
568
} else {
597
569
// put it back in
598
570
backup = Some ( cur_backup) ;
@@ -607,61 +579,72 @@ pub fn best_backup<'a, OS, T>(
607
579
( best, backup)
608
580
}
609
581
610
- /// Alternative, generic version of `fn best_backup`.
611
- ///
612
- /// This method takes any iterator providing Items implementing Ord, such as
613
- /// `OrdRoute`. As such, it has little to do with routes or path selection per
614
- /// se.
615
- ///
616
- /// Note that because of this genericness, we have no access to methods or
617
- /// members of `T`, and thus are unable to compare actual contents such as a
618
- /// `PaMap` or the `TiebreakerInfo`. This means the method can not check for
619
- /// any duplicate route information between `T`s, and really only order them.
620
- /// The caller therefore has to make sure to pass in an iterator that does not
621
- /// yield any duplicate routes.
622
- ///
623
- /// This method enables the caller to attach additional information, as long
624
- /// as it implements `Ord`. For example, one can pass in an iterator over
625
- /// tuples of `OrdRoute` and something else. As long as the `OrdRoute` is the
626
- /// first member of that tuple and no duplicates are yielded from the
627
- /// iterator, the additional information is not used in the ordering process
628
- /// but is returned together with the 'best' and 'backup' tuples. This can be
629
- /// useful when the caller needs to relate routes to local IDs or something
630
- /// alike.
631
- ///
632
- pub fn best_backup_generic < I , T > ( it : I ) -> ( Option < T > , Option < T > )
582
+
583
+ // Attaches an index to a (generic) T, only used internally in _best_backup.
584
+ type RouteWithIndex < T > = ( usize , T ) ;
585
+
586
+ // Internal version doing the heavy lifting for both best_backup and
587
+ // best_backup_position. Returns both the routes themselves (T) and their
588
+ // index (usize).
589
+ fn _best_backup < ' a , I , T , OS > ( it : I )
590
+ -> ( Option < RouteWithIndex < T > > , Option < RouteWithIndex < T > > )
633
591
where
592
+ OS : OrdStrat ,
634
593
I : Iterator < Item = T > ,
635
- T : Ord
594
+ T : Ord + core :: borrow :: Borrow < OrdRoute < ' a , OS > >
636
595
{
637
- let mut best = None ;
638
- let mut backup = None ;
596
+ let mut best: Option < RouteWithIndex < T > > = None ;
597
+ let mut backup: Option < RouteWithIndex < T > > = None ;
639
598
640
- for c in it {
599
+ for ( idx , c ) in it. enumerate ( ) {
641
600
match best. take ( ) {
642
- None => { best = Some ( c ) ; continue }
643
- Some ( cur_best) => {
601
+ None => { best = Some ( ( idx , c ) ) ; continue }
602
+ Some ( ( idx_best , cur_best) ) => {
644
603
if c < cur_best {
645
604
// c is preferred over current best
646
- best = Some ( c ) ;
647
- backup = Some ( cur_best) ;
605
+ best = Some ( ( idx , c ) ) ;
606
+ backup = Some ( ( idx_best , cur_best) ) ;
648
607
continue ;
649
608
}
650
609
// put it back in
651
- best = Some ( cur_best) ;
610
+ best = Some ( ( idx_best , cur_best) ) ;
652
611
653
612
// c is not better than best, now check backup
654
613
match backup. take ( ) {
655
- None => { backup = Some ( c) ; }
656
- Some ( cur_backup) => {
614
+ None => {
615
+ // Before we set the backup route, ensure it is not
616
+ // the same route as best.
617
+ // We compare the actual contents of the OrdRoute
618
+ // here, i.e. the TiebreakerInfo and PaMap. If we'd
619
+ // simply compare the OrdRoutes themselves, we'd be
620
+ // testing whether or not they are considered equal in
621
+ // terms of path preference, NOT in terms of content.
622
+ // If for example we have a candidate backup path with
623
+ // a different AS_PATH but of equal length as the best
624
+ // path, the OrdRoutes are considered equal even
625
+ // though the actual path attributes differ.
626
+ //
627
+
628
+ // `best` is always Some(..) at this point, but we do
629
+ // an `if let` instead of an `unwrap` anyway.
630
+ if let Some ( ( _, cur_best) ) = best. as_ref ( ) {
631
+ if cur_best. borrow ( ) . inner ( ) != c. borrow ( ) . inner ( )
632
+ {
633
+ backup = Some ( ( idx, c) ) ;
634
+ }
635
+ }
636
+ }
637
+ Some ( ( idx_backup, cur_backup) ) => {
657
638
if c < cur_backup {
658
639
// c is preferred over current backup
659
- backup = Some ( c) ;
660
- } else {
661
- // put it back in
662
- backup = Some ( cur_backup) ;
640
+ // check if it is not the same route as 'best'
641
+ if best. as_ref ( ) . map ( |t| & t. 1 ) != Some ( & c) {
642
+ backup = Some ( ( idx, c) ) ;
643
+ continue ;
644
+ }
663
645
}
664
-
646
+ // put it back in
647
+ backup = Some ( ( idx_backup, cur_backup) ) ;
665
648
}
666
649
}
667
650
}
@@ -671,50 +654,37 @@ where
671
654
( best, backup)
672
655
}
673
656
674
- /*
675
- pub fn best_multistrat<'a, OS1: 'a + OrdStrat, OS2: 'a + OrdStrat, I>(it: I)
676
- -> Option<(OrdRoute<'a, OS1>, OrdRoute<'a, OS2>)>
677
- where
678
- I: Clone + Iterator<Item = OrdRoute<'a, OS1>>,
657
+ /// Returns the 'best' and second-best path.
658
+ ///
659
+ /// If the iterator passed in contains no paths, `(None, None)` is returned.
660
+ /// If the iterator yields only a single item, that will be the 'best' path,
661
+ /// and the 'backup' will be None, i.e. `(Some(best), None)`.
662
+ ///
663
+ /// In all other cases (an iterator yielding two or more non-identical
664
+ /// values), both members of the tuple should be `Some(..)`.
665
+ ///
666
+ /// The returned 'best' path is the same as the path returned by [`fn best`].
667
+ pub fn best_backup < ' a , I , T , OS > ( it : I ) -> ( Option < T > , Option < T > )
668
+ where
669
+ OS : OrdStrat ,
670
+ I : Iterator < Item = T > ,
671
+ T : Ord + core:: borrow:: Borrow < OrdRoute < ' a , OS > >
679
672
{
680
- let res1 = best(it.clone());
681
- let res1 = match res1 {
682
- Some(r) => r,
683
- None => return None
684
- };
685
-
686
- // Given that res1 is not None, `it` is non-empty.
687
- // For a non-empty collection of OrdRoutes, there is always a best, so we
688
- // can unwrap().
689
- let res2 = best_with_strat::<'_, _, OS2, _>(it).unwrap();
690
-
691
- Some((res1, res2))
673
+ let ( best, backup) = _best_backup ( it) ;
674
+ ( best. map ( |b| b. 1 ) , backup. map ( |b| b. 1 ) )
692
675
}
693
- */
694
-
695
- /*
696
- pub fn best_multistrat<'a, I, T1, T2, OS1, OS2>(it: I) -> Option<(T1, T2)>
697
- where
698
- T1: Ord + core::borrow::Borrow<OrdRoute<'a, OS1>>,
699
- T2: Ord,
700
- OS1: OrdStrat,
701
- OS2: OrdStrat,
702
- I: Clone + Iterator<Item = T1>,
676
+
677
+ /// Returns the index of the best and backup paths in the passed iterator.
678
+ pub fn best_backup_position < ' a , I , T , OS > ( it : I )
679
+ -> ( Option < usize > , Option < usize > )
680
+ where
681
+ OS : OrdStrat ,
682
+ I : Iterator < Item = T > ,
683
+ T : Ord + core:: borrow:: Borrow < OrdRoute < ' a , OS > >
703
684
{
704
- let res1 = best(it.clone());
705
- let res1 = match res1 {
706
- Some(r) => r,
707
- None => return None
708
- };
709
-
710
- // Given that res1 is not None, `it` is non-empty.
711
- // For a non-empty collection of OrdRoutes, there is always a best, so we
712
- // can unwrap().
713
- let res2 = best_with_strat::<'_, OS1, OS2, _>(it).unwrap();
714
-
715
- Some((res1, res2))
685
+ let ( best, backup) = _best_backup ( it) ;
686
+ ( best. map ( |b| b. 0 ) , backup. map ( |b| b. 0 ) )
716
687
}
717
- */
718
688
719
689
720
690
0 commit comments