@@ -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 ;
@@ -568,17 +569,27 @@ fn document_short<'a, 'cx: 'a>(
568569 let ( mut summary_html, has_more_content) =
569570 MarkdownSummaryLine ( & s, & item. links ( cx) ) . into_string_with_has_more_content ( ) ;
570571
571- if has_more_content {
572- let link = format ! ( " <a{}>Read more</a>" , assoc_href_attr( item, link, cx) ) ;
572+ let link = if has_more_content {
573+ let link = fmt:: from_fn ( |f| {
574+ write ! (
575+ f,
576+ " <a{}>Read more</a>" ,
577+ assoc_href_attr( item, link, cx) . maybe_display( )
578+ )
579+ } ) ;
573580
574581 if let Some ( idx) = summary_html. rfind ( "</p>" ) {
575- summary_html. insert_str ( idx, & link) ;
582+ summary_html. insert_str ( idx, & link. to_string ( ) ) ;
583+ None
576584 } else {
577- summary_html . push_str ( & link) ;
585+ Some ( link)
578586 }
587+ } else {
588+ None
579589 }
590+ . maybe_display ( ) ;
580591
581- write ! ( f, "<div class='docblock'>{summary_html}</div>" ) ?;
592+ write ! ( f, "<div class='docblock'>{summary_html}{link} </div>" ) ?;
582593 }
583594 Ok ( ( ) )
584595 } )
@@ -788,13 +799,23 @@ pub(crate) fn render_impls(
788799}
789800
790801/// 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 {
802+ fn assoc_href_attr < ' a , ' tcx > (
803+ it : & clean:: Item ,
804+ link : AssocItemLink < ' a > ,
805+ cx : & Context < ' tcx > ,
806+ ) -> Option < impl fmt:: Display + ' a + Captures < ' tcx > > {
792807 let name = it. name . unwrap ( ) ;
793808 let item_type = it. type_ ( ) ;
794809
810+ enum Href < ' a > {
811+ AnchorId ( & ' a str ) ,
812+ Anchor ( ItemType ) ,
813+ Url ( String , ItemType ) ,
814+ }
815+
795816 let href = match link {
796- AssocItemLink :: Anchor ( Some ( ref id) ) => Some ( format ! ( "#{id}" ) ) ,
797- AssocItemLink :: Anchor ( None ) => Some ( format ! ( "#{ item_type}.{name}" ) ) ,
817+ AssocItemLink :: Anchor ( Some ( ref id) ) => Href :: AnchorId ( id ) ,
818+ AssocItemLink :: Anchor ( None ) => Href :: Anchor ( item_type) ,
798819 AssocItemLink :: GotoSource ( did, provided_methods) => {
799820 // We're creating a link from the implementation of an associated item to its
800821 // declaration in the trait declaration.
@@ -814,7 +835,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
814835 } ;
815836
816837 match href ( did. expect_def_id ( ) , cx) {
817- Ok ( ( url, ..) ) => Some ( format ! ( "{ url}#{ item_type}.{name}" ) ) ,
838+ Ok ( ( url, ..) ) => Href :: Url ( url, item_type) ,
818839 // The link is broken since it points to an external crate that wasn't documented.
819840 // Do not create any link in such case. This is better than falling back to a
820841 // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
@@ -826,15 +847,25 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
826847 // those two items are distinct!
827848 // In this scenario, the actual `id` of this impl item would be
828849 // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
829- Err ( HrefError :: DocumentationNotBuilt ) => None ,
830- Err ( _) => Some ( format ! ( "#{ item_type}.{name}" ) ) ,
850+ Err ( HrefError :: DocumentationNotBuilt ) => return None ,
851+ Err ( _) => Href :: Anchor ( item_type) ,
831852 }
832853 }
833854 } ;
834855
856+ let href = fmt:: from_fn ( move |f| match & href {
857+ Href :: AnchorId ( id) => write ! ( f, "#{id}" ) ,
858+ Href :: Url ( url, item_type) => {
859+ write ! ( f, "{url}#{item_type}.{name}" )
860+ }
861+ Href :: Anchor ( item_type) => {
862+ write ! ( f, "#{item_type}.{name}" )
863+ }
864+ } ) ;
865+
835866 // If there is no `href` for the reason explained above, simply do not render it which is valid:
836867 // 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 ( )
868+ Some ( fmt :: from_fn ( move |f| write ! ( f , " href=\" {href}\" " ) ) )
838869}
839870
840871#[ derive( Debug ) ]
@@ -865,7 +896,7 @@ fn assoc_const(
865896 "{indent}{vis}const <a{href} class=\" constant\" >{name}</a>{generics}: {ty}" ,
866897 indent = " " . repeat( indent) ,
867898 vis = visibility_print_with_space( it, cx) ,
868- href = assoc_href_attr( it, link, cx) ,
899+ href = assoc_href_attr( it, link, cx) . maybe_display ( ) ,
869900 name = it. name. as_ref( ) . unwrap( ) ,
870901 generics = generics. print( cx) ,
871902 ty = ty. print( cx) ,
@@ -905,7 +936,7 @@ fn assoc_type(
905936 "{indent}{vis}type <a{href} class=\" associatedtype\" >{name}</a>{generics}" ,
906937 indent = " " . repeat( indent) ,
907938 vis = visibility_print_with_space( it, cx) ,
908- href = assoc_href_attr( it, link, cx) ,
939+ href = assoc_href_attr( it, link, cx) . maybe_display ( ) ,
909940 name = it. name. as_ref( ) . unwrap( ) ,
910941 generics = generics. print( cx) ,
911942 ) ,
@@ -948,7 +979,7 @@ fn assoc_method(
948979 let asyncness = header. asyncness . print_with_space ( ) ;
949980 let safety = header. safety . print_with_space ( ) ;
950981 let abi = print_abi_with_space ( header. abi ) . to_string ( ) ;
951- let href = assoc_href_attr ( meth, link, cx) ;
982+ let href = assoc_href_attr ( meth, link, cx) . maybe_display ( ) ;
952983
953984 // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
954985 let generics_len = format ! ( "{:#}" , g. print( cx) ) . len ( ) ;
@@ -962,7 +993,7 @@ fn assoc_method(
962993 + name. as_str ( ) . len ( )
963994 + generics_len;
964995
965- let notable_traits = notable_traits_button ( & d. output , cx) ;
996+ let notable_traits = notable_traits_button ( & d. output , cx) . maybe_display ( ) ;
966997
967998 let ( indent, indent_str, end_newline) = if parent == ItemType :: Trait {
968999 header_len += 4 ;
@@ -990,7 +1021,6 @@ fn assoc_method(
9901021 name = name,
9911022 generics = g. print( cx) ,
9921023 decl = d. full_print( header_len, indent, cx) ,
993- notable_traits = notable_traits. unwrap_or_default( ) ,
9941024 where_clause = print_where_clause( g, cx, indent, end_newline) ,
9951025 ) ,
9961026 ) ;
@@ -1438,7 +1468,10 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
14381468 }
14391469}
14401470
1441- pub ( crate ) fn notable_traits_button ( ty : & clean:: Type , cx : & Context < ' _ > ) -> Option < String > {
1471+ pub ( crate ) fn notable_traits_button < ' a , ' tcx > (
1472+ ty : & ' a clean:: Type ,
1473+ cx : & ' a Context < ' tcx > ,
1474+ ) -> Option < impl fmt:: Display + ' a + Captures < ' tcx > > {
14421475 let mut has_notable_trait = false ;
14431476
14441477 if ty. is_unit ( ) {
@@ -1480,15 +1513,16 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Optio
14801513 }
14811514 }
14821515
1483- if has_notable_trait {
1516+ has_notable_trait. then ( || {
14841517 cx. types_with_notable_traits . borrow_mut ( ) . insert ( ty. clone ( ) ) ;
1485- Some ( format ! (
1486- " <a href=\" #\" class=\" tooltip\" data-notable-ty=\" {ty}\" >ⓘ</a>" ,
1487- ty = Escape ( & format!( "{:#}" , ty. print( cx) ) ) ,
1488- ) )
1489- } else {
1490- None
1491- }
1518+ fmt:: from_fn ( |f| {
1519+ write ! (
1520+ f,
1521+ " <a href=\" #\" class=\" tooltip\" data-notable-ty=\" {ty}\" >ⓘ</a>" ,
1522+ ty = Escape ( & format!( "{:#}" , ty. print( cx) ) ) ,
1523+ )
1524+ } )
1525+ } )
14921526}
14931527
14941528fn notable_traits_decl ( ty : & clean:: Type , cx : & Context < ' _ > ) -> ( String , String ) {
@@ -2117,11 +2151,11 @@ pub(crate) fn render_impl_summary(
21172151) {
21182152 let inner_impl = i. inner_impl ( ) ;
21192153 let id = cx. derive_id ( get_id_for_impl ( cx. tcx ( ) , i. impl_item . item_id ) ) ;
2120- let aliases = if aliases. is_empty ( ) {
2121- String :: new ( )
2122- } else {
2123- format ! ( " data-aliases= \" {} \" " , aliases . join ( "," ) )
2124- } ;
2154+ let aliases = ( ! aliases. is_empty ( ) )
2155+ . then_some ( fmt :: from_fn ( |f| {
2156+ write ! ( f , " data-aliases= \" {} \" " , fmt :: from_fn ( |f| aliases . iter ( ) . joined ( "," , f ) ) )
2157+ } ) )
2158+ . maybe_display ( ) ;
21252159 write_str ( w, format_args ! ( "<section id=\" {id}\" class=\" impl\" {aliases}>" ) ) ;
21262160 render_rightside ( w, cx, & i. impl_item , RenderMode :: Normal ) ;
21272161 write_str (
0 commit comments