@@ -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 ;
@@ -567,7 +568,8 @@ fn document_short<'a, 'cx: 'a>(
567568 MarkdownSummaryLine ( & s, & item. links ( cx) ) . into_string_with_has_more_content ( ) ;
568569
569570 if has_more_content {
570- let link = format ! ( " <a{}>Read more</a>" , assoc_href_attr( item, link, cx) ) ;
571+ let link =
572+ format ! ( " <a{}>Read more</a>" , assoc_href_attr( item, link, cx) . maybe_display( ) ) ;
571573
572574 if let Some ( idx) = summary_html. rfind ( "</p>" ) {
573575 summary_html. insert_str ( idx, & link) ;
@@ -786,13 +788,23 @@ pub(crate) fn render_impls(
786788}
787789
788790/// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
789- fn assoc_href_attr ( it : & clean:: Item , link : AssocItemLink < ' _ > , cx : & Context < ' _ > ) -> String {
791+ fn assoc_href_attr < ' a , ' tcx > (
792+ it : & clean:: Item ,
793+ link : AssocItemLink < ' a > ,
794+ cx : & Context < ' tcx > ,
795+ ) -> Option < impl fmt:: Display + ' a + Captures < ' tcx > > {
790796 let name = it. name . unwrap ( ) ;
791797 let item_type = it. type_ ( ) ;
792798
799+ enum Href < ' a > {
800+ AnchorId ( & ' a str ) ,
801+ Anchor ( ItemType ) ,
802+ Url ( String , ItemType ) ,
803+ }
804+
793805 let href = match link {
794- AssocItemLink :: Anchor ( Some ( ref id) ) => Some ( format ! ( "#{id}" ) ) ,
795- AssocItemLink :: Anchor ( None ) => Some ( format ! ( "#{ item_type}.{name}" ) ) ,
806+ AssocItemLink :: Anchor ( Some ( ref id) ) => Href :: AnchorId ( id ) ,
807+ AssocItemLink :: Anchor ( None ) => Href :: Anchor ( item_type) ,
796808 AssocItemLink :: GotoSource ( did, provided_methods) => {
797809 // We're creating a link from the implementation of an associated item to its
798810 // declaration in the trait declaration.
@@ -812,7 +824,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
812824 } ;
813825
814826 match href ( did. expect_def_id ( ) , cx) {
815- Ok ( ( url, ..) ) => Some ( format ! ( "{ url}#{ item_type}.{name}" ) ) ,
827+ Ok ( ( url, ..) ) => Href :: Url ( url, item_type) ,
816828 // The link is broken since it points to an external crate that wasn't documented.
817829 // Do not create any link in such case. This is better than falling back to a
818830 // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
@@ -824,15 +836,25 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
824836 // those two items are distinct!
825837 // In this scenario, the actual `id` of this impl item would be
826838 // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
827- Err ( HrefError :: DocumentationNotBuilt ) => None ,
828- Err ( _) => Some ( format ! ( "#{ item_type}.{name}" ) ) ,
839+ Err ( HrefError :: DocumentationNotBuilt ) => return None ,
840+ Err ( _) => Href :: Anchor ( item_type) ,
829841 }
830842 }
831843 } ;
832844
845+ let href = fmt:: from_fn ( move |f| match & href {
846+ Href :: AnchorId ( id) => write ! ( f, "#{id}" ) ,
847+ Href :: Url ( url, item_type) => {
848+ write ! ( f, "{url}#{item_type}.{name}" )
849+ }
850+ Href :: Anchor ( item_type) => {
851+ write ! ( f, "#{item_type}.{name}" )
852+ }
853+ } ) ;
854+
833855 // If there is no `href` for the reason explained above, simply do not render it which is valid:
834856 // https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
835- href . map ( |href| format ! ( " href=\" {href}\" " ) ) . unwrap_or_default ( )
857+ Some ( fmt :: from_fn ( move |f| write ! ( f , " href=\" {href}\" " ) ) )
836858}
837859
838860#[ derive( Debug ) ]
@@ -862,7 +884,7 @@ fn assoc_const(
862884 "{indent}{vis}const <a{href} class=\" constant\" >{name}</a>{generics}: {ty}" ,
863885 indent = " " . repeat( indent) ,
864886 vis = visibility_print_with_space( it, cx) ,
865- href = assoc_href_attr( it, link, cx) ,
887+ href = assoc_href_attr( it, link, cx) . maybe_display ( ) ,
866888 name = it. name. as_ref( ) . unwrap( ) ,
867889 generics = generics. print( cx) ,
868890 ty = ty. print( cx) ,
@@ -900,7 +922,7 @@ fn assoc_type(
900922 "{indent}{vis}type <a{href} class=\" associatedtype\" >{name}</a>{generics}" ,
901923 indent = " " . repeat( indent) ,
902924 vis = visibility_print_with_space( it, cx) ,
903- href = assoc_href_attr( it, link, cx) ,
925+ href = assoc_href_attr( it, link, cx) . maybe_display ( ) ,
904926 name = it. name. as_ref( ) . unwrap( ) ,
905927 generics = generics. print( cx) ,
906928 ) ;
@@ -942,7 +964,7 @@ fn assoc_method(
942964 let asyncness = header. asyncness . print_with_space ( ) ;
943965 let safety = header. safety . print_with_space ( ) ;
944966 let abi = print_abi_with_space ( header. abi ) . to_string ( ) ;
945- let href = assoc_href_attr ( meth, link, cx) ;
967+ let href = assoc_href_attr ( meth, link, cx) . maybe_display ( ) ;
946968
947969 // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
948970 let generics_len = format ! ( "{:#}" , g. print( cx) ) . len ( ) ;
0 commit comments