@@ -19,6 +19,7 @@ use rustc_middle::ty;
1919use rustc_middle:: ty:: DefIdTree ;
2020use rustc_middle:: ty:: TyCtxt ;
2121use rustc_span:: def_id:: CRATE_DEF_INDEX ;
22+ use rustc_span:: { sym, Symbol } ;
2223use rustc_target:: spec:: abi:: Abi ;
2324
2425use crate :: clean:: {
@@ -29,6 +30,7 @@ use crate::formats::item_type::ItemType;
2930use crate :: html:: escape:: Escape ;
3031use crate :: html:: render:: Context ;
3132
33+ use super :: url_parts_builder:: estimate_item_path_byte_length;
3234use super :: url_parts_builder:: UrlPartsBuilder ;
3335
3436crate trait Print {
@@ -502,11 +504,22 @@ crate enum HrefError {
502504 NotInExternalCache ,
503505}
504506
507+ // Panics if `syms` is empty.
508+ crate fn join_with_double_colon ( syms : & [ Symbol ] ) -> String {
509+ let mut s = String :: with_capacity ( estimate_item_path_byte_length ( syms. len ( ) ) ) ;
510+ s. push_str ( & syms[ 0 ] . as_str ( ) ) ;
511+ for sym in & syms[ 1 ..] {
512+ s. push_str ( "::" ) ;
513+ s. push_str ( & sym. as_str ( ) ) ;
514+ }
515+ s
516+ }
517+
505518crate fn href_with_root_path (
506519 did : DefId ,
507520 cx : & Context < ' _ > ,
508521 root_path : Option < & str > ,
509- ) -> Result < ( String , ItemType , Vec < String > ) , HrefError > {
522+ ) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
510523 let tcx = cx. tcx ( ) ;
511524 let def_kind = tcx. def_kind ( did) ;
512525 let did = match def_kind {
@@ -518,7 +531,7 @@ crate fn href_with_root_path(
518531 } ;
519532 let cache = cx. cache ( ) ;
520533 let relative_to = & cx. current ;
521- fn to_module_fqp ( shortty : ItemType , fqp : & [ String ] ) -> & [ String ] {
534+ fn to_module_fqp ( shortty : ItemType , fqp : & [ Symbol ] ) -> & [ Symbol ] {
522535 if shortty == ItemType :: Module { fqp } else { & fqp[ ..fqp. len ( ) - 1 ] }
523536 }
524537
@@ -533,9 +546,9 @@ crate fn href_with_root_path(
533546 let mut is_remote = false ;
534547 let ( fqp, shortty, mut url_parts) = match cache. paths . get ( & did) {
535548 Some ( & ( ref fqp, shortty) ) => ( fqp, shortty, {
536- let module_fqp = to_module_fqp ( shortty, fqp) ;
549+ let module_fqp = to_module_fqp ( shortty, fqp. as_slice ( ) ) ;
537550 debug ! ( ?fqp, ?shortty, ?module_fqp) ;
538- href_relative_parts ( module_fqp, relative_to)
551+ href_relative_parts ( module_fqp, relative_to) . collect ( )
539552 } ) ,
540553 None => {
541554 if let Some ( & ( ref fqp, shortty) ) = cache. external_paths . get ( & did) {
@@ -548,10 +561,12 @@ crate fn href_with_root_path(
548561 is_remote = true ;
549562 let s = s. trim_end_matches ( '/' ) ;
550563 let mut builder = UrlPartsBuilder :: singleton ( s) ;
551- builder. extend ( module_fqp. iter ( ) . map ( String :: as_str ) ) ;
564+ builder. extend ( module_fqp. iter ( ) . copied ( ) ) ;
552565 builder
553566 }
554- ExternalLocation :: Local => href_relative_parts ( module_fqp, relative_to) ,
567+ ExternalLocation :: Local => {
568+ href_relative_parts ( module_fqp, relative_to) . collect ( )
569+ }
555570 ExternalLocation :: Unknown => return Err ( HrefError :: DocumentationNotBuilt ) ,
556571 } ,
557572 )
@@ -567,45 +582,50 @@ crate fn href_with_root_path(
567582 }
568583 }
569584 debug ! ( ?url_parts) ;
570- let last = & fqp. last ( ) . unwrap ( ) [ ..] ;
571585 match shortty {
572586 ItemType :: Module => {
573587 url_parts. push ( "index.html" ) ;
574588 }
575589 _ => {
576- let filename = format ! ( "{}.{}.html" , shortty. as_str( ) , last) ;
577- url_parts. push ( & filename) ;
590+ let prefix = shortty. as_str ( ) ;
591+ let last = fqp. last ( ) . unwrap ( ) ;
592+ url_parts. push_fmt ( format_args ! ( "{}.{}.html" , prefix, last) ) ;
578593 }
579594 }
580595 Ok ( ( url_parts. finish ( ) , shortty, fqp. to_vec ( ) ) )
581596}
582597
583- crate fn href ( did : DefId , cx : & Context < ' _ > ) -> Result < ( String , ItemType , Vec < String > ) , HrefError > {
598+ crate fn href ( did : DefId , cx : & Context < ' _ > ) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
584599 href_with_root_path ( did, cx, None )
585600}
586601
587602/// Both paths should only be modules.
588603/// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will
589604/// 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 {
605+ crate fn href_relative_parts < ' fqp > (
606+ fqp : & ' fqp [ Symbol ] ,
607+ relative_to_fqp : & [ Symbol ] ,
608+ ) -> Box < dyn Iterator < Item = Symbol > + ' fqp > {
591609 for ( i, ( f, r) ) in fqp. iter ( ) . zip ( relative_to_fqp. iter ( ) ) . enumerate ( ) {
592610 // e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1)
593611 if f != r {
594612 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 ( ) ;
613+ let fqp_module = & fqp[ i..fqp. len ( ) ] ;
614+ return box iter:: repeat ( sym:: dotdot)
615+ . take ( dissimilar_part_count)
616+ . chain ( fqp_module. iter ( ) . copied ( ) ) ;
597617 }
598618 }
599619 // e.g. linking to std::sync::atomic from std::sync
600620 if relative_to_fqp. len ( ) < fqp. len ( ) {
601- fqp[ relative_to_fqp. len ( ) ..fqp. len ( ) ] . iter ( ) . map ( String :: as_str ) . collect ( )
621+ box fqp[ relative_to_fqp. len ( ) ..fqp. len ( ) ] . iter ( ) . copied ( )
602622 // e.g. linking to std::sync from std::sync::atomic
603623 } else if fqp. len ( ) < relative_to_fqp. len ( ) {
604624 let dissimilar_part_count = relative_to_fqp. len ( ) - fqp. len ( ) ;
605- iter:: repeat ( ".." ) . take ( dissimilar_part_count) . collect ( )
625+ box iter:: repeat ( sym :: dotdot ) . take ( dissimilar_part_count)
606626 // linking to the same module
607627 } else {
608- UrlPartsBuilder :: new ( )
628+ box iter :: empty ( )
609629 }
610630}
611631
@@ -632,14 +652,14 @@ fn resolved_path<'cx>(
632652 if let Ok ( ( _, _, fqp) ) = href ( did, cx) {
633653 format ! (
634654 "{}::{}" ,
635- fqp[ ..fqp. len( ) - 1 ] . join ( "::" ) ,
636- anchor( did, fqp. last( ) . unwrap( ) , cx)
655+ join_with_double_colon ( & fqp[ ..fqp. len( ) - 1 ] ) ,
656+ anchor( did, * fqp. last( ) . unwrap( ) , cx)
637657 )
638658 } else {
639659 last. name . to_string ( )
640660 }
641661 } else {
642- anchor ( did, last. name . as_str ( ) , cx) . to_string ( )
662+ anchor ( did, last. name , cx) . to_string ( )
643663 } ;
644664 write ! ( w, "{}{}" , path, last. args. print( cx) ) ?;
645665 }
@@ -668,30 +688,31 @@ fn primitive_link(
668688 needs_termination = true ;
669689 }
670690 Some ( & def_id) => {
671- let cname_sym;
672691 let loc = match m. extern_locations [ & def_id. krate ] {
673692 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( ) ] )
693+ let cname_sym = ExternalCrate { crate_num : def_id. krate } . name ( cx. tcx ( ) ) ;
694+ let builder: UrlPartsBuilder =
695+ [ s. as_str ( ) . trim_end_matches ( '/' ) , cname_sym. as_str ( ) ]
696+ . into_iter ( )
697+ . collect ( ) ;
698+ Some ( builder)
676699 }
677700 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 ( )
701+ let cname_sym = ExternalCrate { crate_num : def_id. krate } . name ( cx. tcx ( ) ) ;
702+ Some ( if cx. current . first ( ) == Some ( & cname_sym) {
703+ iter:: repeat ( sym :: dotdot ) . take ( cx. current . len ( ) - 1 ) . collect ( )
681704 } else {
682- let cname = iter:: once ( cname_sym. as_str ( ) ) ;
683- iter:: repeat ( ".." ) . take ( cx. current . len ( ) ) . chain ( cname) . collect ( )
705+ iter:: repeat ( sym:: dotdot)
706+ . take ( cx. current . len ( ) )
707+ . chain ( iter:: once ( cname_sym) )
708+ . collect ( )
684709 } )
685710 }
686711 ExternalLocation :: Unknown => None ,
687712 } ;
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- ) ?;
713+ if let Some ( mut loc) = loc {
714+ loc. push_fmt ( format_args ! ( "primitive.{}.html" , prim. as_sym( ) ) ) ;
715+ write ! ( f, "<a class=\" primitive\" href=\" {}\" >" , loc. finish( ) ) ?;
695716 needs_termination = true ;
696717 }
697718 }
@@ -730,7 +751,7 @@ fn tybounds<'a, 'tcx: 'a>(
730751
731752crate fn anchor < ' a , ' cx : ' a > (
732753 did : DefId ,
733- text : & ' a str ,
754+ text : Symbol ,
734755 cx : & ' cx Context < ' _ > ,
735756) -> impl fmt:: Display + ' a {
736757 let parts = href ( did, cx) ;
@@ -742,8 +763,8 @@ crate fn anchor<'a, 'cx: 'a>(
742763 short_ty,
743764 url,
744765 short_ty,
745- fqp . join ( "::" ) ,
746- text
766+ join_with_double_colon ( & fqp ) ,
767+ text. as_str ( )
747768 )
748769 } else {
749770 write ! ( f, "{}" , text)
@@ -960,7 +981,7 @@ fn fmt_type<'cx>(
960981 url = url,
961982 shortty = ItemType :: AssocType ,
962983 name = name,
963- path = path . join ( "::" )
984+ path = join_with_double_colon ( path ) ,
964985 ) ?;
965986 }
966987 _ => write ! ( f, "{}" , name) ?,
@@ -1270,7 +1291,7 @@ impl clean::Visibility {
12701291 debug ! ( "path={:?}" , path) ;
12711292 // modified from `resolved_path()` to work with `DefPathData`
12721293 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 ( ) ;
1294+ let anchor = anchor ( vis_did, last_name, cx) . to_string ( ) ;
12741295
12751296 let mut s = "pub(in " . to_owned ( ) ;
12761297 for seg in & path. data [ ..path. data . len ( ) - 1 ] {
0 commit comments