@@ -63,6 +63,7 @@ pub(crate) use self::context::*;
6363pub ( crate ) use self :: span_map:: { LinkFromSrc , collect_spans_and_sources} ;
6464pub ( crate ) use self :: write_shared:: * ;
6565use crate :: clean:: { self , ItemId , RenderedLink } ;
66+ use crate :: display:: MaybeDisplay as _;
6667use crate :: error:: Error ;
6768use crate :: formats:: Impl ;
6869use crate :: formats:: cache:: Cache ;
@@ -569,7 +570,8 @@ fn document_short<'a, 'cx: 'a>(
569570 MarkdownSummaryLine ( & s, & item. links ( cx) ) . into_string_with_has_more_content ( ) ;
570571
571572 if has_more_content {
572- let link = format ! ( " <a{}>Read more</a>" , assoc_href_attr( item, link, cx) ) ;
573+ let link =
574+ format ! ( " <a{}>Read more</a>" , assoc_href_attr( item, link, cx) . maybe_display( ) ) ;
573575
574576 if let Some ( idx) = summary_html. rfind ( "</p>" ) {
575577 summary_html. insert_str ( idx, & link) ;
@@ -788,13 +790,23 @@ pub(crate) fn render_impls(
788790}
789791
790792/// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
791- fn assoc_href_attr ( it : & clean:: Item , link : AssocItemLink < ' _ > , cx : & Context < ' _ > ) -> String {
793+ fn assoc_href_attr < ' a , ' tcx > (
794+ it : & clean:: Item ,
795+ link : AssocItemLink < ' a > ,
796+ cx : & Context < ' tcx > ,
797+ ) -> Option < impl fmt:: Display + ' a + Captures < ' tcx > > {
792798 let name = it. name . unwrap ( ) ;
793799 let item_type = it. type_ ( ) ;
794800
801+ enum Href < ' a > {
802+ AnchorId ( & ' a str ) ,
803+ Anchor ( ItemType ) ,
804+ Url ( String , ItemType ) ,
805+ }
806+
795807 let href = match link {
796- AssocItemLink :: Anchor ( Some ( ref id) ) => Some ( format ! ( "#{id}" ) ) ,
797- AssocItemLink :: Anchor ( None ) => Some ( format ! ( "#{ item_type}.{name}" ) ) ,
808+ AssocItemLink :: Anchor ( Some ( ref id) ) => Href :: AnchorId ( id ) ,
809+ AssocItemLink :: Anchor ( None ) => Href :: Anchor ( item_type) ,
798810 AssocItemLink :: GotoSource ( did, provided_methods) => {
799811 // We're creating a link from the implementation of an associated item to its
800812 // declaration in the trait declaration.
@@ -814,7 +826,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
814826 } ;
815827
816828 match href ( did. expect_def_id ( ) , cx) {
817- Ok ( ( url, ..) ) => Some ( format ! ( "{ url}#{ item_type}.{name}" ) ) ,
829+ Ok ( ( url, ..) ) => Href :: Url ( url, item_type) ,
818830 // The link is broken since it points to an external crate that wasn't documented.
819831 // Do not create any link in such case. This is better than falling back to a
820832 // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
@@ -826,15 +838,25 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
826838 // those two items are distinct!
827839 // In this scenario, the actual `id` of this impl item would be
828840 // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
829- Err ( HrefError :: DocumentationNotBuilt ) => None ,
830- Err ( _) => Some ( format ! ( "#{ item_type}.{name}" ) ) ,
841+ Err ( HrefError :: DocumentationNotBuilt ) => return None ,
842+ Err ( _) => Href :: Anchor ( item_type) ,
831843 }
832844 }
833845 } ;
834846
847+ let href = fmt:: from_fn ( move |f| match & href {
848+ Href :: AnchorId ( id) => write ! ( f, "#{id}" ) ,
849+ Href :: Url ( url, item_type) => {
850+ write ! ( f, "{url}#{item_type}.{name}" )
851+ }
852+ Href :: Anchor ( item_type) => {
853+ write ! ( f, "#{item_type}.{name}" )
854+ }
855+ } ) ;
856+
835857 // If there is no `href` for the reason explained above, simply do not render it which is valid:
836858 // https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
837- href . map ( |href| format ! ( " href=\" {href}\" " ) ) . unwrap_or_default ( )
859+ Some ( fmt :: from_fn ( move |f| write ! ( f , " href=\" {href}\" " ) ) )
838860}
839861
840862#[ derive( Debug ) ]
@@ -865,7 +887,7 @@ fn assoc_const(
865887 "{indent}{vis}const <a{href} class=\" constant\" >{name}</a>{generics}: {ty}" ,
866888 indent = " " . repeat( indent) ,
867889 vis = visibility_print_with_space( it, cx) ,
868- href = assoc_href_attr( it, link, cx) ,
890+ href = assoc_href_attr( it, link, cx) . maybe_display ( ) ,
869891 name = it. name. as_ref( ) . unwrap( ) ,
870892 generics = generics. print( cx) ,
871893 ty = ty. print( cx) ,
@@ -905,7 +927,7 @@ fn assoc_type(
905927 "{indent}{vis}type <a{href} class=\" associatedtype\" >{name}</a>{generics}" ,
906928 indent = " " . repeat( indent) ,
907929 vis = visibility_print_with_space( it, cx) ,
908- href = assoc_href_attr( it, link, cx) ,
930+ href = assoc_href_attr( it, link, cx) . maybe_display ( ) ,
909931 name = it. name. as_ref( ) . unwrap( ) ,
910932 generics = generics. print( cx) ,
911933 ) ,
@@ -948,7 +970,7 @@ fn assoc_method(
948970 let asyncness = header. asyncness . print_with_space ( ) ;
949971 let safety = header. safety . print_with_space ( ) ;
950972 let abi = print_abi_with_space ( header. abi ) . to_string ( ) ;
951- let href = assoc_href_attr ( meth, link, cx) ;
973+ let href = assoc_href_attr ( meth, link, cx) . maybe_display ( ) ;
952974
953975 // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
954976 let generics_len = format ! ( "{:#}" , g. print( cx) ) . len ( ) ;
0 commit comments