Skip to content

Commit

Permalink
Fill in "Implementors" section in navbar
Browse files Browse the repository at this point in the history
  • Loading branch information
aDotInTheVoid committed Nov 27, 2021
1 parent 65f3f8b commit fe6b0b8
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 68 deletions.
4 changes: 4 additions & 0 deletions src/librustdoc/formats/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,8 @@ impl Impl {
crate fn trait_did(&self) -> Option<DefId> {
self.inner_impl().trait_.as_ref().map(|t| t.def_id())
}

crate fn is_local(&self, cache: &cache::Cache) -> bool {
self.inner_impl().for_.def_id(cache).map_or(true, |d| cache.paths.contains_key(&d))
}
}
6 changes: 5 additions & 1 deletion src/librustdoc/html/render/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ crate struct Context<'tcx> {
pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>,
/// The map used to ensure all generated 'id=' attributes are unique.
pub(super) id_map: RefCell<IdMap>,
/// Converts the rustc id of an item to the html id so we can link to it
pub(super) item_to_html_id_map: RefCell<FxHashMap<clean::ItemId, String>>,
/// Shared mutable state.
///
/// Issue for improving the situation: [#82381][]
Expand All @@ -73,7 +75,7 @@ crate struct Context<'tcx> {

// `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Context<'_>, 144);
rustc_data_structures::static_assert_size!(Context<'_>, 184);

/// Shared mutable state used in [`Context`] and elsewhere.
crate struct SharedContext<'tcx> {
Expand Down Expand Up @@ -517,6 +519,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
render_redirect_pages: false,
id_map: RefCell::new(id_map),
deref_id_map: RefCell::new(FxHashMap::default()),
item_to_html_id_map: RefCell::new(FxHashMap::default()),
shared: Rc::new(scx),
include_sources,
};
Expand All @@ -541,6 +544,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
dst: self.dst.clone(),
render_redirect_pages: self.render_redirect_pages,
deref_id_map: RefCell::new(FxHashMap::default()),
item_to_html_id_map: RefCell::new(FxHashMap::default()),
id_map: RefCell::new(IdMap::new()),
shared: Rc::clone(&self.shared),
include_sources: self.include_sources,
Expand Down
148 changes: 84 additions & 64 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,7 @@ fn render_impl(
);
write!(w, "<summary>")
}

render_impl_summary(
w,
cx,
Expand Down Expand Up @@ -1691,7 +1692,7 @@ pub(crate) fn render_impl_summary(
// in documentation pages for trait with automatic implementations like "Send" and "Sync".
aliases: &[String],
) {
let id = cx.derive_id(match i.inner_impl().trait_ {
let html_id = cx.derive_id(match i.inner_impl().trait_ {
Some(ref t) => {
if is_on_foreign_type {
get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
Expand All @@ -1701,14 +1702,17 @@ pub(crate) fn render_impl_summary(
}
None => "impl".to_string(),
});

cx.item_to_html_id_map.borrow_mut().insert(i.impl_item.def_id, html_id.clone());

let aliases = if aliases.is_empty() {
String::new()
} else {
format!(" data-aliases=\"{}\"", aliases.join(","))
};
write!(w, "<div id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
write!(w, "<div id=\"{}\" class=\"impl has-srclink\"{}>", html_id, aliases);
render_rightside(w, cx, &i.impl_item, containing_item);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", html_id);
write!(w, "<h3 class=\"code-header in-band\">");

if let Some(use_absolute) = use_absolute {
Expand Down Expand Up @@ -2214,20 +2218,12 @@ fn get_id_for_impl_on_foreign_type(
small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx)))
}

fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
match *item.kind {
clean::ItemKind::ImplItem(ref i) => {
i.trait_.as_ref().map(|trait_| {
// Alternative format produces no URLs,
// so this parameter does nothing.
(
format!("{:#}", i.for_.print(cx)),
get_id_for_impl_on_foreign_type(&i.for_, trait_, cx),
)
})
}
_ => None,
}
fn extract_for_impl_name(item: &Impl, cx: &Context<'_>) -> (String, String) {
let i = item.inner_impl();
let trait_ = i.trait_.as_ref().unwrap();
// Alternative format produces no URLs,
// so this parameter does nothing.
(format!("{:#}", i.for_.print(cx)), get_id_for_impl_on_foreign_type(&i.for_, trait_, cx))
}

fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
Expand All @@ -2236,101 +2232,125 @@ fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean
fn print_sidebar_section(
out: &mut Buffer,
items: &[clean::Item],
before: &str,
title: &str,
id: &str,
filter: impl Fn(&clean::Item) -> bool,
write: impl Fn(&mut Buffer, &str),
after: &str,
) {
let mut items = items
.iter()
.filter_map(|m| match m.name {
Some(ref name) if filter(m) => Some(name.as_str()),
_ => None,
})
.collect::<Vec<_>>();
print_sidebar_section_with(
out,
title,
id,
items.iter().filter(|i| filter(i)).filter_map(|i| i.name.map(|n| n.as_str())),
|buf, s| write(buf, &s),
)
}

fn print_sidebar_section_with<T: Ord>(
out: &mut Buffer,
title: &str,
id: &str,
iter: impl Iterator<Item = T>,
write: impl Fn(&mut Buffer, T),
) {
let mut items = iter.collect::<Vec<_>>();

if !items.is_empty() {
items.sort_unstable();
out.push_str(before);
write!(
out,
"<h3 class=\"sidebar-title\"><a href=\"#{}\">\
{}</a></h3><div class=\"sidebar-links\">",
id, title
);
for item in items.into_iter() {
write(out, &item);
write(out, item);
}
out.push_str(after);
out.push_str("</div>");
}
}

print_sidebar_section(
buf,
&t.items,
"<h3 class=\"sidebar-title\"><a href=\"#associated-types\">\
Associated Types</a></h3><div class=\"sidebar-links\">",
"Associated Types",
"associated-types",
|m| m.is_associated_type(),
|out, sym| write!(out, "<a href=\"#associatedtype.{0}\">{0}</a>", sym),
"</div>",
);

print_sidebar_section(
buf,
&t.items,
"<h3 class=\"sidebar-title\"><a href=\"#associated-const\">\
Associated Constants</a></h3><div class=\"sidebar-links\">",
"Associated Constants",
"associated-const",
|m| m.is_associated_const(),
|out, sym| write!(out, "<a href=\"#associatedconstant.{0}\">{0}</a>", sym),
"</div>",
);

print_sidebar_section(
buf,
&t.items,
"<h3 class=\"sidebar-title\"><a href=\"#required-methods\">\
Required Methods</a></h3><div class=\"sidebar-links\">",
"Required Methods",
"required-methods",
|m| m.is_ty_method(),
|out, sym| write!(out, "<a href=\"#tymethod.{0}\">{0}</a>", sym),
"</div>",
);

print_sidebar_section(
buf,
&t.items,
"<h3 class=\"sidebar-title\"><a href=\"#provided-methods\">\
Provided Methods</a></h3><div class=\"sidebar-links\">",
"Provided Methods",
"provided-methods",
|m| m.is_method(),
|out, sym| write!(out, "<a href=\"#method.{0}\">{0}</a>", sym),
"</div>",
);

let cache = cx.cache();
if let Some(implementors) = cache.implementors.get(&it.def_id.expect_def_id()) {
let mut res = implementors
.iter()
.filter(|i| {
i.inner_impl().for_.def_id(cache).map_or(false, |d| !cache.paths.contains_key(&d))
})
.filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
.collect::<Vec<_>>();

if !res.is_empty() {
res.sort();
buf.push_str(
"<h3 class=\"sidebar-title\"><a href=\"#foreign-impls\">\
Implementations on Foreign Types</a></h3>\
<div class=\"sidebar-links\">",
);
for (name, id) in res.into_iter() {
write!(buf, "<a href=\"#{}\">{}</a>", id, Escape(&name));
}
buf.push_str("</div>");
}
}
let did = it.def_id.expect_def_id();

let (local_impl, foreign_impls) = cache
.implementors
.get(&did)
.iter()
.flat_map(|x| *x)
.partition::<Vec<_>, _>(|i| i.is_local(cache));

print_sidebar_section_with(
buf,
"Implementations on Foreign Types",
"foreign-impls",
foreign_impls.iter().map(|i| extract_for_impl_name(i, cx)),
|buf, (name, id)| write!(buf, "<a href=\"#{}\">{}</a>", id, Escape(&name)),
);

sidebar_assoc_items(cx, buf, it);

buf.push_str("<h3 class=\"sidebar-title\"><a href=\"#implementors\">Implementors</a></h3>");
print_sidebar_section_with(
buf,
"Implementors",
"implementors",
local_impl.iter().filter(|i| i.inner_impl().polarity == ty::ImplPolarity::Positive).map(
|i| {
(
format!("{:#}", i.inner_impl().for_.print(cx)),
cx.item_to_html_id_map
.borrow()
.get(&i.impl_item.def_id)
.unwrap_or_else(|| panic!("Not in index {:#?}", i))
.clone(),
)
},
),
|buf, (name, id)| write!(buf, "<a href=\"#{}\">{}</a>", id, Escape(&name)),
);

if t.is_auto {
buf.push_str(
"<h3 class=\"sidebar-title\"><a \
href=\"#synthetic-implementors\">Auto Implementors</a></h3>",
);
// FIXME: List Auto Implementors
}

buf.push_str("</div>")
Expand Down
5 changes: 2 additions & 3 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -741,9 +741,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
}
}

let (local, foreign) = implementors.iter().partition::<Vec<_>, _>(|i| {
i.inner_impl().for_.def_id(cache).map_or(true, |d| cache.paths.contains_key(&d))
});
let (local, foreign) = implementors.iter().partition::<Vec<_>, _>(|i| i.is_local(cache));

let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
local.iter().partition(|i| i.inner_impl().kind.is_auto());
Expand Down Expand Up @@ -784,6 +782,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
"Implementors",
"<div class=\"item-list\" id=\"implementors-list\">",
);

for implementor in concrete {
render_implementor(cx, implementor, it, w, &implementor_dups, &[]);
}
Expand Down

0 comments on commit fe6b0b8

Please sign in to comment.