@@ -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 ;
@@ -566,17 +567,27 @@ fn document_short<'a, 'cx: 'a>(
566
567
let ( mut summary_html, has_more_content) =
567
568
MarkdownSummaryLine ( & s, & item. links ( cx) ) . into_string_with_has_more_content ( ) ;
568
569
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
+ } ) ;
571
578
572
579
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
574
582
} else {
575
- summary_html . push_str ( & link) ;
583
+ Some ( link)
576
584
}
585
+ } else {
586
+ None
577
587
}
588
+ . maybe_display ( ) ;
578
589
579
- write ! ( f, "<div class='docblock'>{summary_html}</div>" ) ?;
590
+ write ! ( f, "<div class='docblock'>{summary_html}{link} </div>" ) ?;
580
591
}
581
592
Ok ( ( ) )
582
593
} )
@@ -786,13 +797,23 @@ pub(crate) fn render_impls(
786
797
}
787
798
788
799
/// 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 > > {
790
805
let name = it. name . unwrap ( ) ;
791
806
let item_type = it. type_ ( ) ;
792
807
808
+ enum Href < ' a > {
809
+ AnchorId ( & ' a str ) ,
810
+ Anchor ( ItemType ) ,
811
+ Url ( String , ItemType ) ,
812
+ }
813
+
793
814
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) ,
796
817
AssocItemLink :: GotoSource ( did, provided_methods) => {
797
818
// We're creating a link from the implementation of an associated item to its
798
819
// declaration in the trait declaration.
@@ -812,7 +833,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
812
833
} ;
813
834
814
835
match href ( did. expect_def_id ( ) , cx) {
815
- Ok ( ( url, ..) ) => Some ( format ! ( "{ url}#{ item_type}.{name}" ) ) ,
836
+ Ok ( ( url, ..) ) => Href :: Url ( url, item_type) ,
816
837
// The link is broken since it points to an external crate that wasn't documented.
817
838
// Do not create any link in such case. This is better than falling back to a
818
839
// 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<'_>)
824
845
// those two items are distinct!
825
846
// In this scenario, the actual `id` of this impl item would be
826
847
// `#{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) ,
829
850
}
830
851
}
831
852
} ;
832
853
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
+
833
864
// If there is no `href` for the reason explained above, simply do not render it which is valid:
834
865
// 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}\" " ) ) )
836
867
}
837
868
838
869
#[ derive( Debug ) ]
@@ -862,7 +893,7 @@ fn assoc_const(
862
893
"{indent}{vis}const <a{href} class=\" constant\" >{name}</a>{generics}: {ty}" ,
863
894
indent = " " . repeat( indent) ,
864
895
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 ( ) ,
866
897
name = it. name. as_ref( ) . unwrap( ) ,
867
898
generics = generics. print( cx) ,
868
899
ty = ty. print( cx) ,
@@ -900,7 +931,7 @@ fn assoc_type(
900
931
"{indent}{vis}type <a{href} class=\" associatedtype\" >{name}</a>{generics}" ,
901
932
indent = " " . repeat( indent) ,
902
933
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 ( ) ,
904
935
name = it. name. as_ref( ) . unwrap( ) ,
905
936
generics = generics. print( cx) ,
906
937
) ;
@@ -942,7 +973,7 @@ fn assoc_method(
942
973
let asyncness = header. asyncness . print_with_space ( ) ;
943
974
let safety = header. safety . print_with_space ( ) ;
944
975
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 ( ) ;
946
977
947
978
// NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
948
979
let generics_len = format ! ( "{:#}" , g. print( cx) ) . len ( ) ;
@@ -956,7 +987,7 @@ fn assoc_method(
956
987
+ name. as_str ( ) . len ( )
957
988
+ generics_len;
958
989
959
- let notable_traits = notable_traits_button ( & d. output , cx) ;
990
+ let notable_traits = notable_traits_button ( & d. output , cx) . maybe_display ( ) ;
960
991
961
992
let ( indent, indent_str, end_newline) = if parent == ItemType :: Trait {
962
993
header_len += 4 ;
@@ -983,7 +1014,6 @@ fn assoc_method(
983
1014
name = name,
984
1015
generics = g. print( cx) ,
985
1016
decl = d. full_print( header_len, indent, cx) ,
986
- notable_traits = notable_traits. unwrap_or_default( ) ,
987
1017
where_clause = print_where_clause( g, cx, indent, end_newline) ,
988
1018
) ;
989
1019
}
@@ -1431,7 +1461,10 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
1431
1461
}
1432
1462
}
1433
1463
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 > > {
1435
1468
let mut has_notable_trait = false ;
1436
1469
1437
1470
if ty. is_unit ( ) {
@@ -1473,15 +1506,16 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Optio
1473
1506
}
1474
1507
}
1475
1508
1476
- if has_notable_trait {
1509
+ has_notable_trait. then ( || {
1477
1510
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
+ } )
1485
1519
}
1486
1520
1487
1521
fn notable_traits_decl ( ty : & clean:: Type , cx : & Context < ' _ > ) -> ( String , String ) {
@@ -2073,11 +2107,11 @@ pub(crate) fn render_impl_summary(
2073
2107
) {
2074
2108
let inner_impl = i. inner_impl ( ) ;
2075
2109
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 ( ) ;
2081
2115
write ! ( w, "<section id=\" {id}\" class=\" impl\" {aliases}>" ) ;
2082
2116
render_rightside ( w, cx, & i. impl_item , RenderMode :: Normal ) ;
2083
2117
write ! (
0 commit comments