Skip to content

Commit 4c1a2c8

Browse files
committed
librustdoc: make assoc_href_attr formatting lazy
1 parent cfdca5f commit 4c1a2c8

File tree

1 file changed

+33
-11
lines changed
  • src/librustdoc/html/render

1 file changed

+33
-11
lines changed

src/librustdoc/html/render/mod.rs

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ pub(crate) use self::context::*;
6363
pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources};
6464
pub(crate) use self::write_shared::*;
6565
use crate::clean::{self, ItemId, RenderedLink};
66+
use crate::display::MaybeDisplay as _;
6667
use crate::error::Error;
6768
use crate::formats::Impl;
6869
use crate::formats::cache::Cache;
@@ -567,7 +568,8 @@ fn document_short<'a, 'cx: 'a>(
567568
MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content();
568569

569570
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());
571573

572574
if let Some(idx) = summary_html.rfind("</p>") {
573575
summary_html.insert_str(idx, &link);
@@ -786,13 +788,23 @@ pub(crate) fn render_impls(
786788
}
787789

788790
/// 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>> {
790796
let name = it.name.unwrap();
791797
let item_type = it.type_();
792798

799+
enum Href<'a> {
800+
AnchorId(&'a str),
801+
Anchor(ItemType),
802+
Url(String, ItemType),
803+
}
804+
793805
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),
796808
AssocItemLink::GotoSource(did, provided_methods) => {
797809
// We're creating a link from the implementation of an associated item to its
798810
// declaration in the trait declaration.
@@ -812,7 +824,7 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
812824
};
813825

814826
match href(did.expect_def_id(), cx) {
815-
Ok((url, ..)) => Some(format!("{url}#{item_type}.{name}")),
827+
Ok((url, ..)) => Href::Url(url, item_type),
816828
// The link is broken since it points to an external crate that wasn't documented.
817829
// Do not create any link in such case. This is better than falling back to a
818830
// 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<'_>)
824836
// those two items are distinct!
825837
// In this scenario, the actual `id` of this impl item would be
826838
// `#{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),
829841
}
830842
}
831843
};
832844

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+
833855
// If there is no `href` for the reason explained above, simply do not render it which is valid:
834856
// 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}\"")))
836858
}
837859

838860
#[derive(Debug)]
@@ -862,7 +884,7 @@ fn assoc_const(
862884
"{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
863885
indent = " ".repeat(indent),
864886
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(),
866888
name = it.name.as_ref().unwrap(),
867889
generics = generics.print(cx),
868890
ty = ty.print(cx),
@@ -900,7 +922,7 @@ fn assoc_type(
900922
"{indent}{vis}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
901923
indent = " ".repeat(indent),
902924
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(),
904926
name = it.name.as_ref().unwrap(),
905927
generics = generics.print(cx),
906928
);
@@ -942,7 +964,7 @@ fn assoc_method(
942964
let asyncness = header.asyncness.print_with_space();
943965
let safety = header.safety.print_with_space();
944966
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();
946968

947969
// NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
948970
let generics_len = format!("{:#}", g.print(cx)).len();

0 commit comments

Comments
 (0)