@@ -19,6 +19,7 @@ use rustc_middle::ty;
19
19
use rustc_middle:: ty:: DefIdTree ;
20
20
use rustc_middle:: ty:: TyCtxt ;
21
21
use rustc_span:: def_id:: CRATE_DEF_INDEX ;
22
+ use rustc_span:: { sym, Symbol } ;
22
23
use rustc_target:: spec:: abi:: Abi ;
23
24
24
25
use crate :: clean:: {
@@ -502,11 +503,45 @@ crate enum HrefError {
502
503
NotInExternalCache ,
503
504
}
504
505
506
+ // This mostly works with sequences of symbols, but sometimes the first item
507
+ // comes from a string, and in that case we want to trim any trailing `/`.
508
+ // `syms` can be empty.
509
+ crate fn join_with_slash ( first : Option < & str > , syms : & [ Symbol ] ) -> String {
510
+ // 64 bytes covers 99.9%+ of cases.
511
+ let mut s = String :: with_capacity ( 64 ) ;
512
+ if let Some ( first) = first {
513
+ s. push_str ( first. trim_end_matches ( '/' ) ) ;
514
+ if !syms. is_empty ( ) {
515
+ s. push ( '/' ) ;
516
+ }
517
+ }
518
+ if !syms. is_empty ( ) {
519
+ s. push_str ( & syms[ 0 ] . as_str ( ) ) ;
520
+ for sym in & syms[ 1 ..] {
521
+ s. push ( '/' ) ;
522
+ s. push_str ( & sym. as_str ( ) ) ;
523
+ }
524
+ }
525
+ s
526
+ }
527
+
528
+ // Panics if `syms` is empty.
529
+ crate fn join_with_double_colon ( syms : & [ Symbol ] ) -> String {
530
+ // 64 bytes covers 99.9%+ of cases.
531
+ let mut s = String :: with_capacity ( 64 ) ;
532
+ s. push_str ( & syms[ 0 ] . as_str ( ) ) ;
533
+ for sym in & syms[ 1 ..] {
534
+ s. push_str ( "::" ) ;
535
+ s. push_str ( & sym. as_str ( ) ) ;
536
+ }
537
+ s
538
+ }
539
+
505
540
crate fn href_with_root_path (
506
541
did : DefId ,
507
542
cx : & Context < ' _ > ,
508
543
root_path : Option < & str > ,
509
- ) -> Result < ( String , ItemType , Vec < String > ) , HrefError > {
544
+ ) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
510
545
let tcx = cx. tcx ( ) ;
511
546
let def_kind = tcx. def_kind ( did) ;
512
547
let did = match def_kind {
@@ -518,7 +553,7 @@ crate fn href_with_root_path(
518
553
} ;
519
554
let cache = cx. cache ( ) ;
520
555
let relative_to = & cx. current ;
521
- fn to_module_fqp ( shortty : ItemType , fqp : & [ String ] ) -> & [ String ] {
556
+ fn to_module_fqp ( shortty : ItemType , fqp : & [ Symbol ] ) -> & [ Symbol ] {
522
557
if shortty == ItemType :: Module { fqp } else { & fqp[ ..fqp. len ( ) - 1 ] }
523
558
}
524
559
@@ -533,9 +568,9 @@ crate fn href_with_root_path(
533
568
let mut is_remote = false ;
534
569
let ( fqp, shortty, mut url_parts) = match cache. paths . get ( & did) {
535
570
Some ( & ( ref fqp, shortty) ) => ( fqp, shortty, {
536
- let module_fqp = to_module_fqp ( shortty, fqp) ;
571
+ let module_fqp = to_module_fqp ( shortty, fqp. as_slice ( ) ) ;
537
572
debug ! ( ?fqp, ?shortty, ?module_fqp) ;
538
- href_relative_parts ( module_fqp, relative_to)
573
+ href_relative_parts ( module_fqp, relative_to) . collect ( )
539
574
} ) ,
540
575
None => {
541
576
if let Some ( & ( ref fqp, shortty) ) = cache. external_paths . get ( & did) {
@@ -548,10 +583,12 @@ crate fn href_with_root_path(
548
583
is_remote = true ;
549
584
let s = s. trim_end_matches ( '/' ) ;
550
585
let mut builder = UrlPartsBuilder :: singleton ( s) ;
551
- builder. extend ( module_fqp. iter ( ) . map ( String :: as_str ) ) ;
586
+ builder. extend ( module_fqp. iter ( ) . copied ( ) ) ;
552
587
builder
553
588
}
554
- ExternalLocation :: Local => href_relative_parts ( module_fqp, relative_to) ,
589
+ ExternalLocation :: Local => {
590
+ href_relative_parts ( module_fqp, relative_to) . collect ( )
591
+ }
555
592
ExternalLocation :: Unknown => return Err ( HrefError :: DocumentationNotBuilt ) ,
556
593
} ,
557
594
)
@@ -567,45 +604,50 @@ crate fn href_with_root_path(
567
604
}
568
605
}
569
606
debug ! ( ?url_parts) ;
570
- let last = & fqp. last ( ) . unwrap ( ) [ ..] ;
571
607
match shortty {
572
608
ItemType :: Module => {
573
609
url_parts. push ( "index.html" ) ;
574
610
}
575
611
_ => {
576
- let filename = format ! ( "{}.{}.html" , shortty. as_str( ) , last) ;
577
- url_parts. push ( & filename) ;
612
+ let prefix = shortty. as_str ( ) ;
613
+ let last = fqp. last ( ) . unwrap ( ) ;
614
+ url_parts. push_fmt ( format_args ! ( "{}.{}.html" , prefix, last) ) ;
578
615
}
579
616
}
580
617
Ok ( ( url_parts. finish ( ) , shortty, fqp. to_vec ( ) ) )
581
618
}
582
619
583
- crate fn href ( did : DefId , cx : & Context < ' _ > ) -> Result < ( String , ItemType , Vec < String > ) , HrefError > {
620
+ crate fn href ( did : DefId , cx : & Context < ' _ > ) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
584
621
href_with_root_path ( did, cx, None )
585
622
}
586
623
587
624
/// Both paths should only be modules.
588
625
/// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will
589
626
/// both need `../iter/trait.Iterator.html` to get at the iterator trait.
590
- crate fn href_relative_parts ( fqp : & [ String ] , relative_to_fqp : & [ String ] ) -> UrlPartsBuilder {
627
+ crate fn href_relative_parts < ' fqp > (
628
+ fqp : & ' fqp [ Symbol ] ,
629
+ relative_to_fqp : & [ Symbol ] ,
630
+ ) -> Box < dyn Iterator < Item = Symbol > + ' fqp > {
591
631
for ( i, ( f, r) ) in fqp. iter ( ) . zip ( relative_to_fqp. iter ( ) ) . enumerate ( ) {
592
632
// e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1)
593
633
if f != r {
594
634
let dissimilar_part_count = relative_to_fqp. len ( ) - i;
595
- let fqp_module = fqp[ i..fqp. len ( ) ] . iter ( ) . map ( String :: as_str) ;
596
- return iter:: repeat ( ".." ) . take ( dissimilar_part_count) . chain ( fqp_module) . collect ( ) ;
635
+ let fqp_module = & fqp[ i..fqp. len ( ) ] ;
636
+ return box iter:: repeat ( sym:: dotdot)
637
+ . take ( dissimilar_part_count)
638
+ . chain ( fqp_module. iter ( ) . copied ( ) ) ;
597
639
}
598
640
}
599
641
// e.g. linking to std::sync::atomic from std::sync
600
642
if relative_to_fqp. len ( ) < fqp. len ( ) {
601
- fqp[ relative_to_fqp. len ( ) ..fqp. len ( ) ] . iter ( ) . map ( String :: as_str ) . collect ( )
643
+ box fqp[ relative_to_fqp. len ( ) ..fqp. len ( ) ] . iter ( ) . copied ( )
602
644
// e.g. linking to std::sync from std::sync::atomic
603
645
} else if fqp. len ( ) < relative_to_fqp. len ( ) {
604
646
let dissimilar_part_count = relative_to_fqp. len ( ) - fqp. len ( ) ;
605
- iter:: repeat ( ".." ) . take ( dissimilar_part_count) . collect ( )
647
+ box iter:: repeat ( sym :: dotdot ) . take ( dissimilar_part_count)
606
648
// linking to the same module
607
649
} else {
608
- UrlPartsBuilder :: new ( )
650
+ box iter :: empty ( )
609
651
}
610
652
}
611
653
@@ -632,14 +674,14 @@ fn resolved_path<'cx>(
632
674
if let Ok ( ( _, _, fqp) ) = href ( did, cx) {
633
675
format ! (
634
676
"{}::{}" ,
635
- fqp[ ..fqp. len( ) - 1 ] . join ( "::" ) ,
636
- anchor( did, fqp. last( ) . unwrap( ) , cx)
677
+ join_with_double_colon ( & fqp[ ..fqp. len( ) - 1 ] ) ,
678
+ anchor( did, * fqp. last( ) . unwrap( ) , cx)
637
679
)
638
680
} else {
639
681
last. name . to_string ( )
640
682
}
641
683
} else {
642
- anchor ( did, last. name . as_str ( ) , cx) . to_string ( )
684
+ anchor ( did, last. name , cx) . to_string ( )
643
685
} ;
644
686
write ! ( w, "{}{}" , path, last. args. print( cx) ) ?;
645
687
}
@@ -668,30 +710,31 @@ fn primitive_link(
668
710
needs_termination = true ;
669
711
}
670
712
Some ( & def_id) => {
671
- let cname_sym;
672
713
let loc = match m. extern_locations [ & def_id. krate ] {
673
714
ExternalLocation :: Remote ( ref s) => {
674
- cname_sym = ExternalCrate { crate_num : def_id. krate } . name ( cx. tcx ( ) ) ;
675
- Some ( vec ! [ s. trim_end_matches( '/' ) , cname_sym. as_str( ) ] )
715
+ let cname_sym = ExternalCrate { crate_num : def_id. krate } . name ( cx. tcx ( ) ) ;
716
+ let builder: UrlPartsBuilder =
717
+ [ s. as_str ( ) . trim_end_matches ( '/' ) , cname_sym. as_str ( ) ]
718
+ . into_iter ( )
719
+ . collect ( ) ;
720
+ Some ( builder)
676
721
}
677
722
ExternalLocation :: Local => {
678
- cname_sym = ExternalCrate { crate_num : def_id. krate } . name ( cx. tcx ( ) ) ;
679
- Some ( if cx. current . first ( ) . map ( |x| & x [ .. ] ) == Some ( cname_sym. as_str ( ) ) {
680
- iter:: repeat ( ".." ) . take ( cx. current . len ( ) - 1 ) . collect ( )
723
+ let cname_sym = ExternalCrate { crate_num : def_id. krate } . name ( cx. tcx ( ) ) ;
724
+ Some ( if cx. current . first ( ) == Some ( & cname_sym) {
725
+ iter:: repeat ( sym :: dotdot ) . take ( cx. current . len ( ) - 1 ) . collect ( )
681
726
} else {
682
- let cname = iter:: once ( cname_sym. as_str ( ) ) ;
683
- iter:: repeat ( ".." ) . take ( cx. current . len ( ) ) . chain ( cname) . collect ( )
727
+ iter:: repeat ( sym:: dotdot)
728
+ . take ( cx. current . len ( ) )
729
+ . chain ( iter:: once ( cname_sym) )
730
+ . collect ( )
684
731
} )
685
732
}
686
733
ExternalLocation :: Unknown => None ,
687
734
} ;
688
- if let Some ( loc) = loc {
689
- write ! (
690
- f,
691
- "<a class=\" primitive\" href=\" {}/primitive.{}.html\" >" ,
692
- loc. join( "/" ) ,
693
- prim. as_sym( )
694
- ) ?;
735
+ if let Some ( mut loc) = loc {
736
+ loc. push_fmt ( format_args ! ( "primitive.{}.html" , prim. as_sym( ) ) ) ;
737
+ write ! ( f, "<a class=\" primitive\" href=\" {}\" >" , loc. finish( ) ) ?;
695
738
needs_termination = true ;
696
739
}
697
740
}
@@ -730,7 +773,7 @@ fn tybounds<'a, 'tcx: 'a>(
730
773
731
774
crate fn anchor < ' a , ' cx : ' a > (
732
775
did : DefId ,
733
- text : & ' a str ,
776
+ text : Symbol ,
734
777
cx : & ' cx Context < ' _ > ,
735
778
) -> impl fmt:: Display + ' a {
736
779
let parts = href ( did, cx) ;
@@ -742,8 +785,8 @@ crate fn anchor<'a, 'cx: 'a>(
742
785
short_ty,
743
786
url,
744
787
short_ty,
745
- fqp . join ( "::" ) ,
746
- text
788
+ join_with_double_colon ( & fqp ) ,
789
+ & * text. as_str ( )
747
790
)
748
791
} else {
749
792
write ! ( f, "{}" , text)
@@ -960,7 +1003,7 @@ fn fmt_type<'cx>(
960
1003
url = url,
961
1004
shortty = ItemType :: AssocType ,
962
1005
name = name,
963
- path = path . join ( "::" )
1006
+ path = join_with_double_colon ( path ) ,
964
1007
) ?;
965
1008
}
966
1009
_ => write ! ( f, "{}" , name) ?,
@@ -1270,7 +1313,7 @@ impl clean::Visibility {
1270
1313
debug ! ( "path={:?}" , path) ;
1271
1314
// modified from `resolved_path()` to work with `DefPathData`
1272
1315
let last_name = path. data . last ( ) . unwrap ( ) . data . get_opt_name ( ) . unwrap ( ) ;
1273
- let anchor = anchor ( vis_did, last_name. as_str ( ) , cx) . to_string ( ) ;
1316
+ let anchor = anchor ( vis_did, last_name, cx) . to_string ( ) ;
1274
1317
1275
1318
let mut s = "pub(in " . to_owned ( ) ;
1276
1319
for seg in & path. data [ ..path. data . len ( ) - 1 ] {
0 commit comments