@@ -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:: { Joined as _, MaybeDisplay as _} ;
6667use crate :: error:: Error ;
6768use crate :: formats:: Impl ;
6869use crate :: formats:: cache:: Cache ;
@@ -566,17 +567,27 @@ fn document_short<'a, 'cx: 'a>(
566567 let ( mut summary_html, has_more_content) =
567568 MarkdownSummaryLine ( & s, & item. links ( cx) ) . into_string_with_has_more_content ( ) ;
568569
569- if has_more_content {
570- let link = format ! ( " <a{}>Read more</a>" , assoc_href_attr( item, link, cx) ) ;
570+ let link = if has_more_content {
571+ let link = fmt:: from_fn ( |f| {
572+ write ! (
573+ f,
574+ " <a{}>Read more</a>" ,
575+ assoc_href_attr( item, link, cx) . maybe_display( )
576+ )
577+ } ) ;
571578
572579 if let Some ( idx) = summary_html. rfind ( "</p>" ) {
573- summary_html. insert_str ( idx, & link) ;
580+ summary_html. insert_str ( idx, & link. to_string ( ) ) ;
581+ None
574582 } else {
575- summary_html . push_str ( & link) ;
583+ Some ( link)
576584 }
585+ } else {
586+ None
577587 }
588+ . maybe_display ( ) ;
578589
579- write ! ( f, "<div class='docblock'>{summary_html}</div>" ) ?;
590+ write ! ( f, "<div class='docblock'>{summary_html}{link} </div>" ) ?;
580591 }
581592 Ok ( ( ) )
582593 } )
@@ -786,13 +797,23 @@ pub(crate) fn render_impls(
786797}
787798
788799/// 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 {
800+ fn assoc_href_attr < ' a , ' tcx > (
801+ it : & clean:: Item ,
802+ link : AssocItemLink < ' a > ,
803+ cx : & Context < ' tcx > ,
804+ ) -> Option < impl fmt:: Display + ' a + Captures < ' tcx > > {
790805 let name = it. name . unwrap ( ) ;
791806 let item_type = it. type_ ( ) ;
792807
808+ enum Href < ' a > {
809+ AnchorId ( & ' a str ) ,
810+ Anchor ( ItemType ) ,
811+ Url ( String , ItemType ) ,
812+ }
813+
793814 let href = match link {
794- AssocItemLink :: Anchor ( Some ( ref id) ) => Some ( format ! ( "#{id}" ) ) ,
795- AssocItemLink :: Anchor ( None ) => Some ( format ! ( "#{ item_type}.{name}" ) ) ,
815+ AssocItemLink :: Anchor ( Some ( ref id) ) => Href :: AnchorId ( id ) ,
816+ AssocItemLink :: Anchor ( None ) => Href :: Anchor ( item_type) ,
796817 AssocItemLink :: GotoSource ( did, provided_methods) => {
797818 // We're creating a link from the implementation of an associated item to its
798819 // declaration in the trait declaration.
@@ -812,7 +833,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
812833 } ;
813834
814835 match href ( did. expect_def_id ( ) , cx) {
815- Ok ( ( url, ..) ) => Some ( format ! ( "{ url}#{ item_type}.{name}" ) ) ,
836+ Ok ( ( url, ..) ) => Href :: Url ( url, item_type) ,
816837 // The link is broken since it points to an external crate that wasn't documented.
817838 // Do not create any link in such case. This is better than falling back to a
818839 // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
@@ -824,15 +845,25 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
824845 // those two items are distinct!
825846 // In this scenario, the actual `id` of this impl item would be
826847 // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
827- Err ( HrefError :: DocumentationNotBuilt ) => None ,
828- Err ( _) => Some ( format ! ( "#{ item_type}.{name}" ) ) ,
848+ Err ( HrefError :: DocumentationNotBuilt ) => return None ,
849+ Err ( _) => Href :: Anchor ( item_type) ,
829850 }
830851 }
831852 } ;
832853
854+ let href = fmt:: from_fn ( move |f| match & href {
855+ Href :: AnchorId ( id) => write ! ( f, "#{id}" ) ,
856+ Href :: Url ( url, item_type) => {
857+ write ! ( f, "{url}#{item_type}.{name}" )
858+ }
859+ Href :: Anchor ( item_type) => {
860+ write ! ( f, "#{item_type}.{name}" )
861+ }
862+ } ) ;
863+
833864 // If there is no `href` for the reason explained above, simply do not render it which is valid:
834865 // 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 ( )
866+ Some ( fmt :: from_fn ( move |f| write ! ( f , " href=\" {href}\" " ) ) )
836867}
837868
838869#[ derive( Debug ) ]
@@ -862,7 +893,7 @@ fn assoc_const(
862893 "{indent}{vis}const <a{href} class=\" constant\" >{name}</a>{generics}: {ty}" ,
863894 indent = " " . repeat( indent) ,
864895 vis = visibility_print_with_space( it, cx) ,
865- href = assoc_href_attr( it, link, cx) ,
896+ href = assoc_href_attr( it, link, cx) . maybe_display ( ) ,
866897 name = it. name. as_ref( ) . unwrap( ) ,
867898 generics = generics. print( cx) ,
868899 ty = ty. print( cx) ,
@@ -900,7 +931,7 @@ fn assoc_type(
900931 "{indent}{vis}type <a{href} class=\" associatedtype\" >{name}</a>{generics}" ,
901932 indent = " " . repeat( indent) ,
902933 vis = visibility_print_with_space( it, cx) ,
903- href = assoc_href_attr( it, link, cx) ,
934+ href = assoc_href_attr( it, link, cx) . maybe_display ( ) ,
904935 name = it. name. as_ref( ) . unwrap( ) ,
905936 generics = generics. print( cx) ,
906937 ) ;
@@ -942,7 +973,7 @@ fn assoc_method(
942973 let asyncness = header. asyncness . print_with_space ( ) ;
943974 let safety = header. safety . print_with_space ( ) ;
944975 let abi = print_abi_with_space ( header. abi ) . to_string ( ) ;
945- let href = assoc_href_attr ( meth, link, cx) ;
976+ let href = assoc_href_attr ( meth, link, cx) . maybe_display ( ) ;
946977
947978 // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
948979 let generics_len = format ! ( "{:#}" , g. print( cx) ) . len ( ) ;
@@ -956,7 +987,7 @@ fn assoc_method(
956987 + name. as_str ( ) . len ( )
957988 + generics_len;
958989
959- let notable_traits = notable_traits_button ( & d. output , cx) ;
990+ let notable_traits = notable_traits_button ( & d. output , cx) . maybe_display ( ) ;
960991
961992 let ( indent, indent_str, end_newline) = if parent == ItemType :: Trait {
962993 header_len += 4 ;
@@ -983,7 +1014,6 @@ fn assoc_method(
9831014 name = name,
9841015 generics = g. print( cx) ,
9851016 decl = d. full_print( header_len, indent, cx) ,
986- notable_traits = notable_traits. unwrap_or_default( ) ,
9871017 where_clause = print_where_clause( g, cx, indent, end_newline) ,
9881018 ) ;
9891019}
@@ -1431,7 +1461,10 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
14311461 }
14321462}
14331463
1434- pub ( crate ) fn notable_traits_button ( ty : & clean:: Type , cx : & Context < ' _ > ) -> Option < String > {
1464+ pub ( crate ) fn notable_traits_button < ' a , ' tcx > (
1465+ ty : & ' a clean:: Type ,
1466+ cx : & ' a Context < ' tcx > ,
1467+ ) -> Option < impl fmt:: Display + ' a + Captures < ' tcx > > {
14351468 let mut has_notable_trait = false ;
14361469
14371470 if ty. is_unit ( ) {
@@ -1473,15 +1506,16 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Optio
14731506 }
14741507 }
14751508
1476- if has_notable_trait {
1509+ has_notable_trait. then ( || {
14771510 cx. types_with_notable_traits . borrow_mut ( ) . insert ( ty. clone ( ) ) ;
1478- Some ( format ! (
1479- " <a href=\" #\" class=\" tooltip\" data-notable-ty=\" {ty}\" >ⓘ</a>" ,
1480- ty = Escape ( & format!( "{:#}" , ty. print( cx) ) ) ,
1481- ) )
1482- } else {
1483- None
1484- }
1511+ fmt:: from_fn ( |f| {
1512+ write ! (
1513+ f,
1514+ " <a href=\" #\" class=\" tooltip\" data-notable-ty=\" {ty}\" >ⓘ</a>" ,
1515+ ty = Escape ( & format!( "{:#}" , ty. print( cx) ) ) ,
1516+ )
1517+ } )
1518+ } )
14851519}
14861520
14871521fn notable_traits_decl ( ty : & clean:: Type , cx : & Context < ' _ > ) -> ( String , String ) {
@@ -2073,11 +2107,11 @@ pub(crate) fn render_impl_summary(
20732107) {
20742108 let inner_impl = i. inner_impl ( ) ;
20752109 let id = cx. derive_id ( get_id_for_impl ( cx. tcx ( ) , i. impl_item . item_id ) ) ;
2076- let aliases = if aliases. is_empty ( ) {
2077- String :: new ( )
2078- } else {
2079- format ! ( " data-aliases= \" {} \" " , aliases . join ( "," ) )
2080- } ;
2110+ let aliases = ( ! aliases. is_empty ( ) )
2111+ . then_some ( fmt :: from_fn ( |f| {
2112+ write ! ( f , " data-aliases= \" {} \" " , fmt :: from_fn ( |f| aliases . iter ( ) . joined ( "," , f ) ) )
2113+ } ) )
2114+ . maybe_display ( ) ;
20812115 write ! ( w, "<section id=\" {id}\" class=\" impl\" {aliases}>" ) ;
20822116 render_rightside ( w, cx, & i. impl_item , RenderMode :: Normal ) ;
20832117 write ! (
0 commit comments