Crate {}
\Version {}
\Back to index
", crate_name, Escape(version), ) } else { String::new() }; let v = layout::render( &self.shared.layout, &page, sidebar, |buf: &mut Buffer| all.print(buf), &self.shared.themes, ); self.shared.fs.write(&final_file, v.as_bytes())?; // Generating settings page. page.title = "Rustdoc settings"; page.description = "Settings of Rustdoc"; page.root_path = "./"; let mut themes = self.shared.themes.clone(); let sidebar = "Settings
"; themes.push(PathBuf::from("settings.css")); let v = layout::render( &self.shared.layout, &page, sidebar, settings( self.shared.static_root_path.as_deref().unwrap_or("./"), &self.shared.resource_suffix, ), &themes, ); self.shared.fs.write(&settings_file, v.as_bytes())?; Ok(()) } fn render_item(&self, it: &clean::Item, pushname: bool) -> String { // A little unfortunate that this is done like this, but it sure // does make formatting *a lot* nicer. CURRENT_DEPTH.with(|slot| { slot.set(self.current.len()); }); let mut title = if it.is_primitive() || it.is_keyword() { // No need to include the namespace for primitive types and keywords String::new() } else { self.current.join("::") }; if pushname { if !title.is_empty() { title.push_str("::"); } title.push_str(it.name.as_ref().unwrap()); } title.push_str(" - Rust"); let tyname = it.type_(); let desc = if it.is_crate() { format!("API documentation for the Rust `{}` crate.", self.shared.layout.krate) } else { format!( "API documentation for the Rust `{}` {} in crate `{}`.", it.name.as_ref().unwrap(), tyname, self.shared.layout.krate ) }; let keywords = make_item_keywords(it); let page = layout::Page { css_class: tyname.as_str(), root_path: &self.root_path(), static_root_path: self.shared.static_root_path.as_deref(), title: &title, description: &desc, keywords: &keywords, resource_suffix: &self.shared.resource_suffix, extra_scripts: &[], static_extra_scripts: &[], }; { self.id_map.borrow_mut().reset(); self.id_map.borrow_mut().populate(initial_ids()); } if !self.render_redirect_pages { layout::render( &self.shared.layout, &page, |buf: &mut _| print_sidebar(self, it, buf), |buf: &mut _| print_item(self, it, buf), &self.shared.themes, ) } else { let mut url = self.root_path(); if let Some(&(ref names, ty)) = self.cache.paths.get(&it.def_id) { for name in &names[..names.len() - 1] { url.push_str(name); url.push_str("/"); } url.push_str(&item_path(ty, names.last().unwrap())); layout::redirect(&url) } else { String::new() } } } /// Non-parallelized version of rendering an item. This will take the input /// item, render its contents, and then invoke the specified closure with /// all sub-items which need to be rendered. /// /// The rendering driver uses this closure to queue up more work. fn itemStruct {{ .. }} syntax; cannot be \
matched against without a wildcard ..; and \
struct update syntax will not work."
);
} else if item.is_enum() {
write!(
w,
"Non-exhaustive enums could have additional variants added in future. \
Therefore, when matching against variants of non-exhaustive enums, an \
extra wildcard arm must be added to account for any future variants."
);
} else if item.is_variant() {
write!(
w,
"Non-exhaustive enum variants could have additional fields added in future. \
Therefore, non-exhaustive enum variants cannot be constructed in external \
crates and cannot be matched against."
);
} else {
write!(
w,
"This type will require a wildcard arm in any match statements or \
constructors."
);
}
write!(w, "{}extern crate {} as {};",
myitem.visibility.print_with_space(),
anchor(myitem.def_id, src),
name
),
None => write!(
w,
" |
{}", Escape(&feature));
if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, stab.issue) {
feature.push_str(&format!(
" #{issue}",
url = url,
issue = issue
));
}
message.push_str(&format!(" ({})", feature));
}
if let Some(unstable_reason) = &stab.unstable_reason {
// Provide a more informative message than the compiler help.
let unstable_reason = if is_rustc_private {
"This crate is being loaded from the sysroot, a permanently unstable location \
for private compiler dependencies. It is not intended for general use. Prefer \
using a public version of this crate from \
[crates.io](https://crates.io) via [`Cargo.toml`]\
(https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html)."
} else {
unstable_reason
};
let mut ids = cx.id_map.borrow_mut();
message = format!(
"");
render_attributes(w, it, false);
write!(
w,
"{vis}const \
{name}: {typ}",
vis = it.visibility.print_with_space(),
name = it.name.as_ref().unwrap(),
typ = c.type_.print(),
);
if c.value.is_some() || c.is_literal {
write!(w, " = {expr};", expr = Escape(&c.expr));
} else {
write!(w, ";");
}
if let Some(value) = &c.value {
if !c.is_literal {
let value_lowercase = value.to_lowercase();
let expr_lowercase = c.expr.to_lowercase();
if value_lowercase != expr_lowercase
&& value_lowercase.trim_end_matches("i32") != expr_lowercase
{
write!(w, " // {value}", value = Escape(value));
}
}
}
write!(w, "");
document(w, cx, it)
}
fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static) {
write!(w, "");
render_attributes(w, it, false);
write!(
w,
"{vis}static {mutability}\
{name}: {typ}",
vis = it.visibility.print_with_space(),
mutability = s.mutability.print_with_space(),
name = it.name.as_ref().unwrap(),
typ = s.type_.print()
);
document(w, cx, it)
}
fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) {
let header_len = format!(
"{}{}{}{}{:#}fn {}{:#}",
it.visibility.print_with_space(),
f.header.constness.print_with_space(),
f.header.asyncness.print_with_space(),
f.header.unsafety.print_with_space(),
print_abi_with_space(f.header.abi),
it.name.as_ref().unwrap(),
f.generics.print()
)
.len();
write!(w, "");
render_attributes(w, it, false);
write!(
w,
"{vis}{constness}{asyncness}{unsafety}{abi}fn \
{name}{generics}{decl}{where_clause}",
vis = it.visibility.print_with_space(),
constness = f.header.constness.print_with_space(),
asyncness = f.header.asyncness.print_with_space(),
unsafety = f.header.unsafety.print_with_space(),
abi = print_abi_with_space(f.header.abi),
name = it.name.as_ref().unwrap(),
generics = f.generics.print(),
where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
decl = Function { decl: &f.decl, header_len, indent: 0, asyncness: f.header.asyncness }
.print()
);
document(w, cx, it)
}
fn render_implementor(
cx: &Context,
implementor: &Impl,
w: &mut Buffer,
implementor_dups: &FxHashMap<&str, (DefId, bool)>,
aliases: &[String],
) {
// If there's already another implementor that has the same abbridged name, use the
// full path, for example in `std::iter::ExactSizeIterator`
let use_absolute = match implementor.inner_impl().for_ {
clean::ResolvedPath { ref path, is_generic: false, .. }
| clean::BorrowedRef {
type_: box clean::ResolvedPath { ref path, is_generic: false, .. },
..
} => implementor_dups[path.last_name()].1,
_ => false,
};
render_impl(
w,
cx,
implementor,
AssocItemLink::Anchor(None),
RenderMode::Normal,
implementor.impl_item.stable_since(),
false,
Some(use_absolute),
false,
false,
aliases,
);
}
fn render_impls(cx: &Context, w: &mut Buffer, traits: &[&&Impl], containing_item: &clean::Item) {
let mut impls = traits
.iter()
.map(|i| {
let did = i.trait_did().unwrap();
let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
render_impl(
&mut buffer,
cx,
i,
assoc_link,
RenderMode::Normal,
containing_item.stable_since(),
true,
None,
false,
true,
&[],
);
buffer.into_inner()
})
.collect::");
render_attributes(w, it, true);
write!(
w,
"{}{}{}trait {}{}{}",
it.visibility.print_with_space(),
t.unsafety.print_with_space(),
if t.is_auto { "auto " } else { "" },
it.name.as_ref().unwrap(),
t.generics.print(),
bounds
);
if !t.generics.where_predicates.is_empty() {
write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true });
} else {
write!(w, " ");
}
if t.items.is_empty() {
write!(w, "{{ }}");
} else {
// FIXME: we should be using a derived_id for the Anchors here
write!(w, "{{\n");
for t in &types {
render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait);
write!(w, ";\n");
}
if !types.is_empty() && !consts.is_empty() {
w.write_str("\n");
}
for t in &consts {
render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait);
write!(w, ";\n");
}
if !consts.is_empty() && !required.is_empty() {
w.write_str("\n");
}
for (pos, m) in required.iter().enumerate() {
render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait);
write!(w, ";\n");
if pos < required.len() - 1 {
write!(w, "");
}
}
if !required.is_empty() && !provided.is_empty() {
w.write_str("\n");
}
for (pos, m) in provided.iter().enumerate() {
render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait);
match m.inner {
clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => {
write!(w, ",\n {{ ... }}\n");
}
_ => {
write!(w, " {{ ... }}\n");
}
}
if pos < provided.len() - 1 {
write!(w, "");
}
}
write!(w, "}}");
}
write!(w, "")
});
// Trait documentation
document(w, cx, it);
fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) {
write!(
w,
"
", id = id, ns_id = ns_id);
render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl);
write!(w, "");
render_stability_since(w, m, t);
write!(w, "");
render_attributes(w, it, true);
render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", true);
write!(w, "")
});
document(w, cx, it);
let mut fields = s
.fields
.iter()
.filter_map(|f| match f.inner {
clean::StructFieldItem(ref ty) => Some((f, ty)),
_ => None,
})
.peekable();
if let doctree::Plain = s.struct_type {
if fields.peek().is_some() {
write!(
w,
"{name}: {ty}\
",
item_type = ItemType::StructField,
id = id,
ns_id = ns_id,
name = field.name.as_ref().unwrap(),
ty = ty.print()
);
document(w, cx, field);
}
}
}
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}
fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union) {
wrap_into_docblock(w, |w| {
write!(w, "");
render_attributes(w, it, true);
render_union(w, it, Some(&s.generics), &s.fields, "", true);
write!(w, "")
});
document(w, cx, it);
let mut fields = s
.fields
.iter()
.filter_map(|f| match f.inner {
clean::StructFieldItem(ref ty) => Some((f, ty)),
_ => None,
})
.peekable();
if fields.peek().is_some() {
write!(
w,
"{name}: {ty}\
",
id = id,
name = name,
shortty = ItemType::StructField,
ty = ty.print()
);
if let Some(stability_class) = field.stability_class() {
write!(w, "", stab = stability_class);
}
document(w, cx, field);
}
}
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}
fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) {
wrap_into_docblock(w, |w| {
write!(w, "");
render_attributes(w, it, true);
write!(
w,
"{}enum {}{}{}",
it.visibility.print_with_space(),
it.name.as_ref().unwrap(),
e.generics.print(),
WhereClause { gens: &e.generics, indent: 0, end_newline: true }
);
if e.variants.is_empty() && !e.variants_stripped {
write!(w, " {{}}");
} else {
write!(w, " {{\n");
for v in &e.variants {
write!(w, " ");
let name = v.name.as_ref().unwrap();
match v.inner {
clean::VariantItem(ref var) => match var.kind {
clean::VariantKind::CLike => write!(w, "{}", name),
clean::VariantKind::Tuple(ref tys) => {
write!(w, "{}(", name);
for (i, ty) in tys.iter().enumerate() {
if i > 0 {
write!(w, ", ")
}
write!(w, "{}", ty.print());
}
write!(w, ")");
}
clean::VariantKind::Struct(ref s) => {
render_struct(w, v, None, s.struct_type, &s.fields, " ", false);
}
},
_ => unreachable!(),
}
write!(w, ",\n");
}
if e.variants_stripped {
write!(w, " // some variants omitted\n");
}
write!(w, "}}");
}
write!(w, "")
});
document(w, cx, it);
if !e.variants.is_empty() {
write!(
w,
"{name}",
id = id,
ns_id = ns_id,
name = variant.name.as_ref().unwrap()
);
if let clean::VariantItem(ref var) = variant.inner {
if let clean::VariantKind::Tuple(ref tys) = var.kind {
write!(w, "(");
for (i, ty) in tys.iter().enumerate() {
if i > 0 {
write!(w, ", ");
}
write!(w, "{}", ty.print());
}
write!(w, ")");
}
}
write!(w, "{f}: {t}\
",
id = id,
ns_id = ns_id,
f = field.name.as_ref().unwrap(),
t = ty.print()
);
document(w, cx, field);
}
}
write!(w, "", id, aliases);
fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute);
if show_def_docs {
for it in &i.inner_impl().items {
if let clean::TypedefItem(ref tydef, _) = it.inner {
write!(w, " ");
assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "");
write!(w, ";");
}
}
}
write!(w, "");
} else {
write!(
w,
"{}",
id,
aliases,
i.inner_impl().print()
);
}
write!(w, "", id);
let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]);
render_stability_since_raw(w, since, outer_version);
if let Some(l) = cx.src_href(&i.impl_item) {
write!(w, "[src]", l, "goto source code");
}
write!(w, "", ns_id);
render_assoc_item(w, item, link.anchor(&id), ItemType::Impl);
write!(w, "");
render_stability_since_raw(w, item.stable_since(), outer_version);
if let Some(l) = cx.src_href(item) {
write!(
w,
"[src]",
l, "goto source code"
);
}
write!(w, "", ns_id);
assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), "");
write!(w, "", ns_id);
assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "");
write!(w, "");
render_stability_since_raw(w, item.stable_since(), outer_version);
if let Some(l) = cx.src_href(item) {
write!(
w,
"[src]",
l, "goto source code"
);
}
write!(w, "", ns_id);
assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), "");
write!(w, "");
render_attributes(w, it, false);
write!(
w,
"type {}{}{where_clause} = impl {bounds};",
it.name.as_ref().unwrap(),
t.generics.print(),
where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
bounds = bounds(&t.bounds, false)
);
document(w, cx, it);
// Render any items associated directly to this alias, as otherwise they
// won't be visible anywhere in the docs. It would be nice to also show
// associated items from the aliased type (see discussion in #32077), but
// we need #14072 to make sense of the generics.
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}
fn item_trait_alias(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::TraitAlias) {
write!(w, "");
render_attributes(w, it, false);
write!(
w,
"trait {}{}{} = {};",
it.name.as_ref().unwrap(),
t.generics.print(),
WhereClause { gens: &t.generics, indent: 0, end_newline: true },
bounds(&t.bounds, true)
);
document(w, cx, it);
// Render any items associated directly to this alias, as otherwise they
// won't be visible anywhere in the docs. It would be nice to also show
// associated items from the aliased type (see discussion in #32077), but
// we need #14072 to make sense of the generics.
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}
fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typedef) {
write!(w, "");
render_attributes(w, it, false);
write!(
w,
"type {}{}{where_clause} = {type_};",
it.name.as_ref().unwrap(),
t.generics.print(),
where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true },
type_ = t.type_.print()
);
document(w, cx, it);
// Render any items associated directly to this alias, as otherwise they
// won't be visible anywhere in the docs. It would be nice to also show
// associated items from the aliased type (see discussion in #32077), but
// we need #14072 to make sense of the generics.
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}
fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item) {
writeln!(w, "extern {{");
render_attributes(w, it, false);
write!(
w,
" {}type {};\n}}",
it.visibility.print_with_space(),
it.name.as_ref().unwrap(),
);
document(w, cx, it);
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}
fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer) {
let parentlen = cx.current.len() - if it.is_mod() { 1 } else { 0 };
if it.is_struct()
|| it.is_trait()
|| it.is_primitive()
|| it.is_union()
|| it.is_enum()
|| it.is_mod()
|| it.is_typedef()
{
write!(
buffer,
"{}{}
", match it.inner { clean::StructItem(..) => "Struct ", clean::TraitItem(..) => "Trait ", clean::PrimitiveItem(..) => "Primitive Type ", clean::UnionItem(..) => "Union ", clean::EnumItem(..) => "Enum ", clean::TypedefItem(..) => "Type Definition ", clean::ForeignTypeItem => "Foreign Type ", clean::ModuleItem(..) => if it.is_crate() { "Crate " } else { "Module " }, _ => "", }, it.name.as_ref().unwrap() ); } if it.is_crate() { if let Some(ref version) = cx.cache.crate_version { write!( buffer, "Version {}
\");
write!(w, "{}!() {{ /* proc-macro */ }}", name);
write!(w, "");
}
MacroKind::Attr => {
write!(w, "");
write!(w, "#[{}]", name);
write!(w, "");
}
MacroKind::Derive => {
write!(w, "");
write!(w, "#[derive({})]", name);
if !m.helpers.is_empty() {
writeln!(w, "\n{{");
writeln!(w, " // Attributes available to this derive:");
for attr in &m.helpers {
writeln!(w, " #[{}]", attr);
}
write!(w, "}}");
}
write!(w, "");
}
}
document(w, cx, it)
}
fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item) {
document(w, cx, it);
render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)
}
fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item) {
document(w, cx, it)
}
crate const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang";
fn make_item_keywords(it: &clean::Item) -> String {
format!("{}, {}", BASIC_KEYWORDS, it.name.as_ref().unwrap())
}
/// Returns a list of all paths used in the type.
/// This is used to help deduplicate imported impls
/// for reexported types. If any of the contained
/// types are re-exported, we don't use the corresponding
/// entry from the js file, as inlining will have already
/// picked up the impl
fn collect_paths_for_type(first_ty: clean::Type) -> Vec