@@ -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 ;
@@ -569,7 +570,8 @@ fn document_short<'a, 'cx: 'a>(
569
570
MarkdownSummaryLine ( & s, & item. links ( cx) ) . into_string_with_has_more_content ( ) ;
570
571
571
572
if has_more_content {
572
- let link = format ! ( " <a{}>Read more</a>" , assoc_href_attr( item, link, cx) ) ;
573
+ let link =
574
+ format ! ( " <a{}>Read more</a>" , assoc_href_attr( item, link, cx) . maybe_display( ) ) ;
573
575
574
576
if let Some ( idx) = summary_html. rfind ( "</p>" ) {
575
577
summary_html. insert_str ( idx, & link) ;
@@ -788,13 +790,23 @@ pub(crate) fn render_impls(
788
790
}
789
791
790
792
/// 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 {
793
+ fn assoc_href_attr < ' a , ' tcx > (
794
+ it : & clean:: Item ,
795
+ link : AssocItemLink < ' a > ,
796
+ cx : & Context < ' tcx > ,
797
+ ) -> Option < impl fmt:: Display + ' a + Captures < ' tcx > > {
792
798
let name = it. name . unwrap ( ) ;
793
799
let item_type = it. type_ ( ) ;
794
800
801
+ enum Href < ' a > {
802
+ AnchorId ( & ' a str ) ,
803
+ Anchor ( ItemType ) ,
804
+ Url ( String , ItemType ) ,
805
+ }
806
+
795
807
let href = match link {
796
- AssocItemLink :: Anchor ( Some ( ref id) ) => Some ( format ! ( "#{id}" ) ) ,
797
- AssocItemLink :: Anchor ( None ) => Some ( format ! ( "#{ item_type}.{name}" ) ) ,
808
+ AssocItemLink :: Anchor ( Some ( ref id) ) => Href :: AnchorId ( id ) ,
809
+ AssocItemLink :: Anchor ( None ) => Href :: Anchor ( item_type) ,
798
810
AssocItemLink :: GotoSource ( did, provided_methods) => {
799
811
// We're creating a link from the implementation of an associated item to its
800
812
// declaration in the trait declaration.
@@ -814,7 +826,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
814
826
} ;
815
827
816
828
match href ( did. expect_def_id ( ) , cx) {
817
- Ok ( ( url, ..) ) => Some ( format ! ( "{ url}#{ item_type}.{name}" ) ) ,
829
+ Ok ( ( url, ..) ) => Href :: Url ( url, item_type) ,
818
830
// The link is broken since it points to an external crate that wasn't documented.
819
831
// Do not create any link in such case. This is better than falling back to a
820
832
// dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
@@ -826,15 +838,25 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
826
838
// those two items are distinct!
827
839
// In this scenario, the actual `id` of this impl item would be
828
840
// `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
829
- Err ( HrefError :: DocumentationNotBuilt ) => None ,
830
- Err ( _) => Some ( format ! ( "#{ item_type}.{name}" ) ) ,
841
+ Err ( HrefError :: DocumentationNotBuilt ) => return None ,
842
+ Err ( _) => Href :: Anchor ( item_type) ,
831
843
}
832
844
}
833
845
} ;
834
846
847
+ let href = fmt:: from_fn ( move |f| match & href {
848
+ Href :: AnchorId ( id) => write ! ( f, "#{id}" ) ,
849
+ Href :: Url ( url, item_type) => {
850
+ write ! ( f, "{url}#{item_type}.{name}" )
851
+ }
852
+ Href :: Anchor ( item_type) => {
853
+ write ! ( f, "#{item_type}.{name}" )
854
+ }
855
+ } ) ;
856
+
835
857
// If there is no `href` for the reason explained above, simply do not render it which is valid:
836
858
// 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 ( )
859
+ Some ( fmt :: from_fn ( move |f| write ! ( f , " href=\" {href}\" " ) ) )
838
860
}
839
861
840
862
#[ derive( Debug ) ]
@@ -865,7 +887,7 @@ fn assoc_const(
865
887
"{indent}{vis}const <a{href} class=\" constant\" >{name}</a>{generics}: {ty}" ,
866
888
indent = " " . repeat( indent) ,
867
889
vis = visibility_print_with_space( it, cx) ,
868
- href = assoc_href_attr( it, link, cx) ,
890
+ href = assoc_href_attr( it, link, cx) . maybe_display ( ) ,
869
891
name = it. name. as_ref( ) . unwrap( ) ,
870
892
generics = generics. print( cx) ,
871
893
ty = ty. print( cx) ,
@@ -905,7 +927,7 @@ fn assoc_type(
905
927
"{indent}{vis}type <a{href} class=\" associatedtype\" >{name}</a>{generics}" ,
906
928
indent = " " . repeat( indent) ,
907
929
vis = visibility_print_with_space( it, cx) ,
908
- href = assoc_href_attr( it, link, cx) ,
930
+ href = assoc_href_attr( it, link, cx) . maybe_display ( ) ,
909
931
name = it. name. as_ref( ) . unwrap( ) ,
910
932
generics = generics. print( cx) ,
911
933
) ,
@@ -948,7 +970,7 @@ fn assoc_method(
948
970
let asyncness = header. asyncness . print_with_space ( ) ;
949
971
let safety = header. safety . print_with_space ( ) ;
950
972
let abi = print_abi_with_space ( header. abi ) . to_string ( ) ;
951
- let href = assoc_href_attr ( meth, link, cx) ;
973
+ let href = assoc_href_attr ( meth, link, cx) . maybe_display ( ) ;
952
974
953
975
// NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
954
976
let generics_len = format ! ( "{:#}" , g. print( cx) ) . len ( ) ;
0 commit comments