@@ -63,6 +63,7 @@ pub(crate) use self::context::*;
63
63
pub ( crate ) use self :: span_map:: { LinkFromSrc , collect_spans_and_sources} ;
64
64
pub ( crate ) use self :: write_shared:: * ;
65
65
use crate :: clean:: { self , ItemId , RenderedLink } ;
66
+ use crate :: display:: { Joined as _, MaybeDisplay as _} ;
66
67
use crate :: error:: Error ;
67
68
use crate :: formats:: Impl ;
68
69
use crate :: formats:: cache:: Cache ;
@@ -568,17 +569,27 @@ fn document_short<'a, 'cx: 'a>(
568
569
let ( mut summary_html, has_more_content) =
569
570
MarkdownSummaryLine ( & s, & item. links ( cx) ) . into_string_with_has_more_content ( ) ;
570
571
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
+ } ) ;
573
580
574
581
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
576
584
} else {
577
- summary_html . push_str ( & link) ;
585
+ Some ( link)
578
586
}
587
+ } else {
588
+ None
579
589
}
590
+ . maybe_display ( ) ;
580
591
581
- write ! ( f, "<div class='docblock'>{summary_html}</div>" ) ?;
592
+ write ! ( f, "<div class='docblock'>{summary_html}{link} </div>" ) ?;
582
593
}
583
594
Ok ( ( ) )
584
595
} )
@@ -788,13 +799,23 @@ pub(crate) fn render_impls(
788
799
}
789
800
790
801
/// 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 > > {
792
807
let name = it. name . unwrap ( ) ;
793
808
let item_type = it. type_ ( ) ;
794
809
810
+ enum Href < ' a > {
811
+ AnchorId ( & ' a str ) ,
812
+ Anchor ( ItemType ) ,
813
+ Url ( String , ItemType ) ,
814
+ }
815
+
795
816
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) ,
798
819
AssocItemLink :: GotoSource ( did, provided_methods) => {
799
820
// We're creating a link from the implementation of an associated item to its
800
821
// declaration in the trait declaration.
@@ -814,7 +835,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
814
835
} ;
815
836
816
837
match href ( did. expect_def_id ( ) , cx) {
817
- Ok ( ( url, ..) ) => Some ( format ! ( "{ url}#{ item_type}.{name}" ) ) ,
838
+ Ok ( ( url, ..) ) => Href :: Url ( url, item_type) ,
818
839
// The link is broken since it points to an external crate that wasn't documented.
819
840
// Do not create any link in such case. This is better than falling back to a
820
841
// 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<'_>)
826
847
// those two items are distinct!
827
848
// In this scenario, the actual `id` of this impl item would be
828
849
// `#{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) ,
831
852
}
832
853
}
833
854
} ;
834
855
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
+
835
866
// If there is no `href` for the reason explained above, simply do not render it which is valid:
836
867
// 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}\" " ) ) )
838
869
}
839
870
840
871
#[ derive( Debug ) ]
@@ -865,7 +896,7 @@ fn assoc_const(
865
896
"{indent}{vis}const <a{href} class=\" constant\" >{name}</a>{generics}: {ty}" ,
866
897
indent = " " . repeat( indent) ,
867
898
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 ( ) ,
869
900
name = it. name. as_ref( ) . unwrap( ) ,
870
901
generics = generics. print( cx) ,
871
902
ty = ty. print( cx) ,
@@ -905,7 +936,7 @@ fn assoc_type(
905
936
"{indent}{vis}type <a{href} class=\" associatedtype\" >{name}</a>{generics}" ,
906
937
indent = " " . repeat( indent) ,
907
938
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 ( ) ,
909
940
name = it. name. as_ref( ) . unwrap( ) ,
910
941
generics = generics. print( cx) ,
911
942
) ,
@@ -948,7 +979,7 @@ fn assoc_method(
948
979
let asyncness = header. asyncness . print_with_space ( ) ;
949
980
let safety = header. safety . print_with_space ( ) ;
950
981
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 ( ) ;
952
983
953
984
// NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
954
985
let generics_len = format ! ( "{:#}" , g. print( cx) ) . len ( ) ;
@@ -962,7 +993,7 @@ fn assoc_method(
962
993
+ name. as_str ( ) . len ( )
963
994
+ generics_len;
964
995
965
- let notable_traits = notable_traits_button ( & d. output , cx) ;
996
+ let notable_traits = notable_traits_button ( & d. output , cx) . maybe_display ( ) ;
966
997
967
998
let ( indent, indent_str, end_newline) = if parent == ItemType :: Trait {
968
999
header_len += 4 ;
@@ -990,7 +1021,6 @@ fn assoc_method(
990
1021
name = name,
991
1022
generics = g. print( cx) ,
992
1023
decl = d. full_print( header_len, indent, cx) ,
993
- notable_traits = notable_traits. unwrap_or_default( ) ,
994
1024
where_clause = print_where_clause( g, cx, indent, end_newline) ,
995
1025
) ,
996
1026
) ;
@@ -1438,7 +1468,10 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
1438
1468
}
1439
1469
}
1440
1470
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 > > {
1442
1475
let mut has_notable_trait = false ;
1443
1476
1444
1477
if ty. is_unit ( ) {
@@ -1480,15 +1513,16 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Optio
1480
1513
}
1481
1514
}
1482
1515
1483
- if has_notable_trait {
1516
+ has_notable_trait. then ( || {
1484
1517
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
+ } )
1492
1526
}
1493
1527
1494
1528
fn notable_traits_decl ( ty : & clean:: Type , cx : & Context < ' _ > ) -> ( String , String ) {
@@ -2117,11 +2151,11 @@ pub(crate) fn render_impl_summary(
2117
2151
) {
2118
2152
let inner_impl = i. inner_impl ( ) ;
2119
2153
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 ( ) ;
2125
2159
write_str ( w, format_args ! ( "<section id=\" {id}\" class=\" impl\" {aliases}>" ) ) ;
2126
2160
render_rightside ( w, cx, & i. impl_item , RenderMode :: Normal ) ;
2127
2161
write_str (
0 commit comments