@@ -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:: MaybeDisplay as _;
66
67
use crate :: error:: Error ;
67
68
use crate :: formats:: Impl ;
68
69
use crate :: formats:: cache:: Cache ;
@@ -567,7 +568,8 @@ fn document_short<'a, 'cx: 'a>(
567
568
MarkdownSummaryLine ( & s, & item. links ( cx) ) . into_string_with_has_more_content ( ) ;
568
569
569
570
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( ) ) ;
571
573
572
574
if let Some ( idx) = summary_html. rfind ( "</p>" ) {
573
575
summary_html. insert_str ( idx, & link) ;
@@ -786,13 +788,23 @@ pub(crate) fn render_impls(
786
788
}
787
789
788
790
/// 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 > > {
790
796
let name = it. name . unwrap ( ) ;
791
797
let item_type = it. type_ ( ) ;
792
798
799
+ enum Href < ' a > {
800
+ AnchorId ( & ' a str ) ,
801
+ Anchor ( ItemType ) ,
802
+ Url ( String , ItemType ) ,
803
+ }
804
+
793
805
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) ,
796
808
AssocItemLink :: GotoSource ( did, provided_methods) => {
797
809
// We're creating a link from the implementation of an associated item to its
798
810
// declaration in the trait declaration.
@@ -812,7 +824,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
812
824
} ;
813
825
814
826
match href ( did. expect_def_id ( ) , cx) {
815
- Ok ( ( url, ..) ) => Some ( format ! ( "{ url}#{ item_type}.{name}" ) ) ,
827
+ Ok ( ( url, ..) ) => Href :: Url ( url, item_type) ,
816
828
// The link is broken since it points to an external crate that wasn't documented.
817
829
// Do not create any link in such case. This is better than falling back to a
818
830
// 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<'_>)
824
836
// those two items are distinct!
825
837
// In this scenario, the actual `id` of this impl item would be
826
838
// `#{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) ,
829
841
}
830
842
}
831
843
} ;
832
844
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
+
833
855
// If there is no `href` for the reason explained above, simply do not render it which is valid:
834
856
// 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}\" " ) ) )
836
858
}
837
859
838
860
#[ derive( Debug ) ]
@@ -862,7 +884,7 @@ fn assoc_const(
862
884
"{indent}{vis}const <a{href} class=\" constant\" >{name}</a>{generics}: {ty}" ,
863
885
indent = " " . repeat( indent) ,
864
886
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 ( ) ,
866
888
name = it. name. as_ref( ) . unwrap( ) ,
867
889
generics = generics. print( cx) ,
868
890
ty = ty. print( cx) ,
@@ -900,7 +922,7 @@ fn assoc_type(
900
922
"{indent}{vis}type <a{href} class=\" associatedtype\" >{name}</a>{generics}" ,
901
923
indent = " " . repeat( indent) ,
902
924
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 ( ) ,
904
926
name = it. name. as_ref( ) . unwrap( ) ,
905
927
generics = generics. print( cx) ,
906
928
) ;
@@ -942,7 +964,7 @@ fn assoc_method(
942
964
let asyncness = header. asyncness . print_with_space ( ) ;
943
965
let safety = header. safety . print_with_space ( ) ;
944
966
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 ( ) ;
946
968
947
969
// NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
948
970
let generics_len = format ! ( "{:#}" , g. print( cx) ) . len ( ) ;
0 commit comments