//! both occur before the crate is rendered.
pub use self::ExternalLocation::*;
+#[cfg(stage0)]
use std::ascii::AsciiExt;
use std::cell::RefCell;
use std::cmp::Ordering;
-use std::collections::BTreeMap;
+use std::collections::{BTreeMap, HashSet};
use std::default::Default;
use std::error;
use std::fmt::{self, Display, Formatter, Write as FmtWrite};
// Figure out the id of this impl. This may map to a
// primitive rather than always to a struct/enum.
// Note: matching twice to restrict the lifetime of the `i` borrow.
- let mut dids = vec![];
+ let mut dids = FxHashSet();
if let clean::Item { inner: clean::ImplItem(ref i), .. } = item {
let masked_trait = i.trait_.def_id().map_or(false,
|d| self.masked_crates.contains(&d.krate));
clean::BorrowedRef {
type_: box clean::ResolvedPath { did, .. }, ..
} => {
- dids.push(did);
+ dids.insert(did);
}
ref t => {
let did = t.primitive_type().and_then(|t| {
});
if let Some(did) = did {
- dids.push(did);
+ dids.insert(did);
}
}
}
if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
for bound in generics {
if let Some(did) = bound.def_id() {
- dids.push(did);
+ dids.insert(did);
}
}
}
document(w, cx, item)?;
let mut indices = (0..items.len()).filter(|i| {
- if let clean::DefaultImplItem(..) = items[*i].inner {
+ if let clean::AutoImplItem(..) = items[*i].inner {
return false;
}
!items[*i].is_stripped()
ItemType::Primitive => ("primitives", "Primitive Types"),
ItemType::AssociatedType => ("associated-types", "Associated Types"),
ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
+ ItemType::ForeignType => ("foreign-types", "Foreign Types"),
};
write!(w, "<h2 id='{id}' class='section-header'>\
<a href=\"#{id}\">{name}</a></h2>\n<table>",
}
}
+fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
+ let self_type_opt = match item.inner {
+ clean::MethodItem(ref method) => method.decl.self_type(),
+ clean::TyMethodItem(ref method) => method.decl.self_type(),
+ _ => None
+ };
+
+ if let Some(self_ty) = self_type_opt {
+ let (by_mut_ref, by_box) = match self_ty {
+ SelfTy::SelfBorrowed(_, mutability) |
+ SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
+ (mutability == Mutability::Mutable, false)
+ },
+ SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
+ (false, Some(did) == cache().owned_box_did)
+ },
+ _ => (false, false),
+ };
+
+ (deref_mut_ || !by_mut_ref) && !by_box
+ } else {
+ false
+ }
+}
+
fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink,
render_mode: RenderMode, outer_version: Option<&str>,
show_def_docs: bool) -> fmt::Result {
if render_mode == RenderMode::Normal {
let id = derive_id(match i.inner_impl().trait_ {
- Some(ref t) => format!("impl-{}", Escape(&format!("{:#}", t))),
+ Some(ref t) => format!("impl-{}", small_url_encode(&format!("{:#}", t))),
None => "impl".to_string(),
});
write!(w, "<h3 id='{}' class='impl'><span class='in-band'><code>{}</code>",
let render_method_item: bool = match render_mode {
RenderMode::Normal => true,
- RenderMode::ForDeref { mut_: deref_mut_ } => {
- let self_type_opt = match item.inner {
- clean::MethodItem(ref method) => method.decl.self_type(),
- clean::TyMethodItem(ref method) => method.decl.self_type(),
- _ => None
- };
-
- if let Some(self_ty) = self_type_opt {
- let (by_mut_ref, by_box) = match self_ty {
- SelfTy::SelfBorrowed(_, mutability) |
- SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
- (mutability == Mutability::Mutable, false)
- },
- SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
- (false, Some(did) == cache().owned_box_did)
- },
- _ => (false, false),
- };
-
- (deref_mut_ || !by_mut_ref) && !by_box
- } else {
- false
- }
- },
+ RenderMode::ForDeref { mut_: deref_mut_ } => should_render_item(&item, deref_mut_),
};
match item.inner {
}
}
+fn get_methods(i: &clean::Impl, for_deref: bool) -> Vec<String> {
+ i.items.iter().filter_map(|item| {
+ match item.name {
+ // Maybe check with clean::Visibility::Public as well?
+ Some(ref name) if !name.is_empty() && item.visibility.is_some() && item.is_method() => {
+ if !for_deref || should_render_item(item, false) {
+ Some(format!("<a href=\"#method.{name}\">{name}</a>", name = name))
+ } else {
+ None
+ }
+ }
+ _ => None,
+ }
+ }).collect::<Vec<_>>()
+}
+
+// The point is to url encode any potential character from a type with genericity.
+fn small_url_encode(s: &str) -> String {
+ s.replace("<", "%3C")
+ .replace(">", "%3E")
+ .replace(" ", "%20")
+ .replace("?", "%3F")
+ .replace("'", "%27")
+ .replace("&", "%26")
+ .replace(",", "%2C")
+ .replace(":", "%3A")
+ .replace(";", "%3B")
+ .replace("[", "%5B")
+ .replace("]", "%5D")
+}
+
fn sidebar_assoc_items(it: &clean::Item) -> String {
let mut out = String::new();
let c = cache();
if let Some(v) = c.impls.get(&it.def_id) {
- if v.iter().any(|i| i.inner_impl().trait_.is_none()) {
- out.push_str("<li><a href=\"#methods\">Methods</a></li>");
+ let ret = v.iter()
+ .filter(|i| i.inner_impl().trait_.is_none())
+ .flat_map(|i| get_methods(i.inner_impl(), false))
+ .collect::<String>();
+ if !ret.is_empty() {
+ out.push_str(&format!("<a class=\"sidebar-title\" href=\"#methods\">Methods\
+ </a><div class=\"sidebar-links\">{}</div>", ret));
}
if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
let inner_impl = target.def_id().or(target.primitive_type().and_then(|prim| {
c.primitive_locations.get(&prim).cloned()
})).and_then(|did| c.impls.get(&did));
- if inner_impl.is_some() {
- out.push_str("<li><a href=\"#deref-methods\">");
+ if let Some(impls) = inner_impl {
+ out.push_str("<a class=\"sidebar-title\" href=\"#deref-methods\">");
out.push_str(&format!("Methods from {:#}<Target={:#}>",
- impl_.inner_impl().trait_.as_ref().unwrap(),
- target));
- out.push_str("</a></li>");
+ impl_.inner_impl().trait_.as_ref().unwrap(),
+ target));
+ out.push_str("</a>");
+ let ret = impls.iter()
+ .filter(|i| i.inner_impl().trait_.is_none())
+ .flat_map(|i| get_methods(i.inner_impl(), true))
+ .collect::<String>();
+ out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", ret));
}
}
}
- out.push_str("<li><a href=\"#implementations\">Trait Implementations</a></li>");
+ let mut links = HashSet::new();
+ let ret = v.iter()
+ .filter_map(|i| if let Some(ref i) = i.inner_impl().trait_ {
+ let out = format!("{:#}", i).replace("<", "<").replace(">", ">");
+ let encoded = small_url_encode(&format!("{:#}", i));
+ let generated = format!("<a href=\"#impl-{}\">{}</a>", encoded, out);
+ if !links.contains(&generated) && links.insert(generated.clone()) {
+ Some(generated)
+ } else {
+ None
+ }
+ } else {
+ None
+ })
+ .collect::<String>();
+ if !ret.is_empty() {
+ out.push_str("<a class=\"sidebar-title\" href=\"#implementations\">\
+ Trait Implementations</a>");
+ out.push_str(&format!("<div class=\"sidebar-links\">{}</div>", ret));
+ }
}
}
sidebar.push_str(&sidebar_assoc_items(it));
if !sidebar.is_empty() {
- write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
+ write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
}
Ok(())
}
sidebar.push_str("<li><a href=\"#provided-methods\">Provided Methods</a></li>");
}
- sidebar.push_str(&sidebar_assoc_items(it));
-
let c = cache();
if let Some(implementors) = c.implementors.get(&it.def_id) {
sidebar.push_str("<li><a href=\"#implementors\">Implementors</a></li>");
- write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)
+ sidebar.push_str(&sidebar_assoc_items(it));
+
+ write!(fmt, "<div class=\"block items\">{}</div>", sidebar)
}
fn sidebar_primitive(fmt: &mut fmt::Formatter, it: &clean::Item,
let sidebar = sidebar_assoc_items(it);
if !sidebar.is_empty() {
- write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
+ write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
}
Ok(())
}
let sidebar = sidebar_assoc_items(it);
if !sidebar.is_empty() {
- write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
+ write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
}
Ok(())
}
sidebar.push_str(&sidebar_assoc_items(it));
if !sidebar.is_empty() {
- write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
+ write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
}
Ok(())
}
sidebar.push_str(&sidebar_assoc_items(it));
if !sidebar.is_empty() {
- write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?;
+ write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?;
}
Ok(())
}
ItemType::Enum, ItemType::Constant, ItemType::Static, ItemType::Trait,
ItemType::Function, ItemType::Typedef, ItemType::Union, ItemType::Impl,
ItemType::TyMethod, ItemType::Method, ItemType::StructField, ItemType::Variant,
- ItemType::AssociatedType, ItemType::AssociatedConst] {
+ ItemType::AssociatedType, ItemType::AssociatedConst, ItemType::ForeignType] {
if items.iter().any(|it| {
- if let clean::DefaultImplItem(..) = it.inner {
+ if let clean::AutoImplItem(..) = it.inner {
false
} else {
!it.is_stripped() && it.type_() == myty
ItemType::Primitive => ("primitives", "Primitive Types"),
ItemType::AssociatedType => ("associated-types", "Associated Types"),
ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
+ ItemType::ForeignType => ("foreign-types", "Foreign Types"),
};
sidebar.push_str(&format!("<li><a href=\"#{id}\">{name}</a></li>",
id = short,