@@ -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:: {
@@ -502,11 +503,45 @@ crate enum HrefError {
502503 NotInExternalCache ,
503504}
504505
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+
505540crate fn href_with_root_path (
506541 did : DefId ,
507542 cx : & Context < ' _ > ,
508543 root_path : Option < & str > ,
509- ) -> Result < ( String , ItemType , Vec < String > ) , HrefError > {
544+ ) -> Result < ( String , ItemType , Vec < Symbol > ) , HrefError > {
510545 let tcx = cx. tcx ( ) ;
511546 let def_kind = tcx. def_kind ( did) ;
512547 let did = match def_kind {
@@ -518,7 +553,7 @@ crate fn href_with_root_path(
518553 } ;
519554 let cache = cx. cache ( ) ;
520555 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 ] {
522557 if shortty == ItemType :: Module { fqp } else { & fqp[ ..fqp. len ( ) - 1 ] }
523558 }
524559
@@ -533,9 +568,9 @@ crate fn href_with_root_path(
533568 let mut is_remote = false ;
534569 let ( fqp, shortty, mut url_parts) = match cache. paths . get ( & did) {
535570 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 ( ) ) ;
537572 debug ! ( ?fqp, ?shortty, ?module_fqp) ;
538- href_relative_parts ( module_fqp, relative_to)
573+ href_relative_parts ( module_fqp, relative_to) . collect ( )
539574 } ) ,
540575 None => {
541576 if let Some ( & ( ref fqp, shortty) ) = cache. external_paths . get ( & did) {
@@ -548,10 +583,12 @@ crate fn href_with_root_path(
548583 is_remote = true ;
549584 let s = s. trim_end_matches ( '/' ) ;
550585 let mut builder = UrlPartsBuilder :: singleton ( s) ;
551- builder. extend ( module_fqp. iter ( ) . map ( String :: as_str ) ) ;
586+ builder. extend ( module_fqp. iter ( ) . copied ( ) ) ;
552587 builder
553588 }
554- ExternalLocation :: Local => href_relative_parts ( module_fqp, relative_to) ,
589+ ExternalLocation :: Local => {
590+ href_relative_parts ( module_fqp, relative_to) . collect ( )
591+ }
555592 ExternalLocation :: Unknown => return Err ( HrefError :: DocumentationNotBuilt ) ,
556593 } ,
557594 )
@@ -567,45 +604,50 @@ crate fn href_with_root_path(
567604 }
568605 }
569606 debug ! ( ?url_parts) ;
570- let last = & fqp. last ( ) . unwrap ( ) [ ..] ;
571607 match shortty {
572608 ItemType :: Module => {
573609 url_parts. push ( "index.html" ) ;
574610 }
575611 _ => {
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) ) ;
578615 }
579616 }
580617 Ok ( ( url_parts. finish ( ) , shortty, fqp. to_vec ( ) ) )
581618}
582619
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 > {
584621 href_with_root_path ( did, cx, None )
585622}
586623
587624/// Both paths should only be modules.
588625/// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will
589626/// 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 > {
591631 for ( i, ( f, r) ) in fqp. iter ( ) . zip ( relative_to_fqp. iter ( ) ) . enumerate ( ) {
592632 // e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1)
593633 if f != r {
594634 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 ( ) ) ;
597639 }
598640 }
599641 // e.g. linking to std::sync::atomic from std::sync
600642 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 ( )
602644 // e.g. linking to std::sync from std::sync::atomic
603645 } else if fqp. len ( ) < relative_to_fqp. len ( ) {
604646 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)
606648 // linking to the same module
607649 } else {
608- UrlPartsBuilder :: new ( )
650+ box iter :: empty ( )
609651 }
610652}
611653
@@ -632,14 +674,14 @@ fn resolved_path<'cx>(
632674 if let Ok ( ( _, _, fqp) ) = href ( did, cx) {
633675 format ! (
634676 "{}::{}" ,
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)
637679 )
638680 } else {
639681 last. name . to_string ( )
640682 }
641683 } else {
642- anchor ( did, last. name . as_str ( ) , cx) . to_string ( )
684+ anchor ( did, last. name , cx) . to_string ( )
643685 } ;
644686 write ! ( w, "{}{}" , path, last. args. print( cx) ) ?;
645687 }
@@ -668,30 +710,31 @@ fn primitive_link(
668710 needs_termination = true ;
669711 }
670712 Some ( & def_id) => {
671- let cname_sym;
672713 let loc = match m. extern_locations [ & def_id. krate ] {
673714 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)
676721 }
677722 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 ( )
681726 } 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 ( )
684731 } )
685732 }
686733 ExternalLocation :: Unknown => None ,
687734 } ;
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( ) ) ?;
695738 needs_termination = true ;
696739 }
697740 }
@@ -730,7 +773,7 @@ fn tybounds<'a, 'tcx: 'a>(
730773
731774crate fn anchor < ' a , ' cx : ' a > (
732775 did : DefId ,
733- text : & ' a str ,
776+ text : Symbol ,
734777 cx : & ' cx Context < ' _ > ,
735778) -> impl fmt:: Display + ' a {
736779 let parts = href ( did, cx) ;
@@ -742,8 +785,8 @@ crate fn anchor<'a, 'cx: 'a>(
742785 short_ty,
743786 url,
744787 short_ty,
745- fqp . join ( "::" ) ,
746- text
788+ join_with_double_colon ( & fqp ) ,
789+ & * text. as_str ( )
747790 )
748791 } else {
749792 write ! ( f, "{}" , text)
@@ -960,7 +1003,7 @@ fn fmt_type<'cx>(
9601003 url = url,
9611004 shortty = ItemType :: AssocType ,
9621005 name = name,
963- path = path . join ( "::" )
1006+ path = join_with_double_colon ( path ) ,
9641007 ) ?;
9651008 }
9661009 _ => write ! ( f, "{}" , name) ?,
@@ -1270,7 +1313,7 @@ impl clean::Visibility {
12701313 debug ! ( "path={:?}" , path) ;
12711314 // modified from `resolved_path()` to work with `DefPathData`
12721315 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 ( ) ;
12741317
12751318 let mut s = "pub(in " . to_owned ( ) ;
12761319 for seg in & path. data [ ..path. data . len ( ) - 1 ] {
0 commit comments