//! Rustdoc's HTML rendering module.
//!
//! This modules contains the bulk of the logic necessary for rendering a
//! rustdoc `clean::Crate` instance to a set of static HTML pages. This
//! rendering process is largely driven by the `format!` syntax extension to
//! perform all I/O into files and streams.
//!
//! The rendering process is largely driven by the `Context` and `Cache`
//! structures. The cache is pre-populated by crawling the crate in question,
//! and then it is shared among the various rendering threads. The cache is meant
//! to be a fairly large structure not implementing `Clone` (because it's shared
//! among threads). The context, however, should be a lightweight structure. This
//! is cloned per-thread and contains information about what is currently being
//! rendered.
//!
//! In order to speed up rendering (mostly because of markdown rendering), the
//! rendering process has been parallelized. This parallelization is only
//! exposed through the `crate` method on the context, and then also from the
//! fact that the shared cache is stored in TLS (and must be accessed as such).
//!
//! In addition to rendering the crate itself, this module is also responsible
//! for creating the corresponding search index and source file renderings.
//! These threads are not parallelized (they haven't been a bottleneck yet), and
//! both occur before the crate is rendered.
crate mod cache;
#[cfg(test)]
mod tests;
mod context;
mod print_item;
mod write_shared;
crate use context::*;
use std::collections::VecDeque;
use std::default::Default;
use std::fmt;
use std::path::PathBuf;
use std::str;
use std::string::ToString;
use rustc_ast_pretty::pprust;
use rustc_attr::{Deprecation, StabilityLevel};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::DefId;
use rustc_hir::Mutability;
use rustc_middle::middle::stability;
use rustc_span::symbol::{kw, sym, Symbol};
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
use crate::clean::{self, FakeDefId, GetDefId, RenderedLink, SelfTy};
use crate::docfs::PathError;
use crate::error::Error;
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
use crate::formats::{AssocItemRender, Impl, RenderMode};
use crate::html::escape::Escape;
use crate::html::format::{
    href, print_abi_with_space, print_default_space, print_generic_bounds, print_where_clause,
    Buffer, PrintWithSpace,
};
use crate::html::markdown::{Markdown, MarkdownHtml, MarkdownSummaryLine};
/// A pair of name and its optional document.
crate type NameDoc = (String, Option(&self, serializer: S) -> Result(&self, serializer: S) -> Result(&self, serializer: S) -> Result(&self, serializer: S) -> Result{}
",
                    title.replace(' ', "-"), // IDs cannot contain whitespaces.
                    title,
                    class
                );
                for s in e.iter() {
                    write!(f, "
");
            }
        }
        f.write_str(
            "\
                 List of all items\
                 \
                     \
                         \
                             [−]\
                         \
                     
                 
             
",
        );
        // Note: print_entries does not escape the title, because we know the current set of titles
        // doesn't require escaping.
        print_entries(f, &self.structs, "Structs", "structs");
        print_entries(f, &self.enums, "Enums", "enums");
        print_entries(f, &self.unions, "Unions", "unions");
        print_entries(f, &self.primitives, "Primitives", "primitives");
        print_entries(f, &self.traits, "Traits", "traits");
        print_entries(f, &self.macros, "Macros", "macros");
        print_entries(f, &self.attributes, "Attribute Macros", "attributes");
        print_entries(f, &self.derives, "Derive Macros", "derives");
        print_entries(f, &self.functions, "Functions", "functions");
        print_entries(f, &self.typedefs, "Typedefs", "typedefs");
        print_entries(f, &self.trait_aliases, "Trait Aliases", "trait-aliases");
        print_entries(f, &self.opaque_tys, "Opaque Types", "opaque-types");
        print_entries(f, &self.statics, "Statics", "statics");
        print_entries(f, &self.constants, "Constants", "constants")
    }
}
#[derive(Debug)]
enum Setting {
    Section {
        description: &'static str,
        sub_settings: Vec\
            Rustdoc settings\
        
\
        
{}", Escape(&feature.as_str()));
        if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) {
            feature.push_str(&format!(
                " #{issue}",
                url = url,
                issue = issue
            ));
        }
        message.push_str(&format!(" ({})", feature));
        if let Some(unstable_reason) = reason {
            let mut ids = cx.id_map.borrow_mut();
            message = format!(
                "` tag, it is formatted using
// a whitespace prefix and newline.
fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
    for a in attributes(it) {
        writeln!(w, "{}{}", prefix, a);
    }
}
// When an attribute is rendered inside a  tag, it is formatted using
// a div to produce a newline after it.
fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
    for a in attributes(it) {
        write!(w, "{}", a);
    }
}
#[derive(Copy, Clone)]
enum AssocItemLink<'a> {
    Anchor(Option<&'a str>),
    GotoSource(FakeDefId, &'a FxHashSet),
}
impl<'a> AssocItemLink<'a> {
    fn anchor(&self, id: &'a str) -> Self {
        match *self {
            AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(&id)),
            ref other => *other,
        }
    }
}
fn render_assoc_items(
    w: &mut Buffer,
    cx: &Context<'_>,
    containing_item: &clean::Item,
    it: DefId,
    what: AssocItemRender<'_>,
) {
    info!("Documenting associated items of {:?}", containing_item.name);
    let v = match cx.cache.impls.get(&it) {
        Some(v) => v,
        None => return,
    };
    let tcx = cx.tcx();
    let cache = cx.cache();
    let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
    if !non_trait.is_empty() {
        let render_mode = match what {
            AssocItemRender::All => {
                w.write_str(
                    "\
                         Implementations\
                    
",
                );
                RenderMode::Normal
            }
            AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
                write!(
                    w,
                    "\
                         Methods from {trait_}<Target = {type_}>\
                         \
                     
",
                    trait_ = trait_.print(cx),
                    type_ = type_.print(cx),
                );
                RenderMode::ForDeref { mut_: deref_mut_ }
            }
        };
        for i in &non_trait {
            render_impl(
                w,
                cx,
                i,
                containing_item,
                AssocItemLink::Anchor(None),
                render_mode,
                containing_item.stable_since(tcx).as_deref(),
                containing_item.const_stable_since(tcx).as_deref(),
                true,
                None,
                false,
                true,
                &[],
            );
        }
    }
    if let AssocItemRender::DerefFor { .. } = what {
        return;
    }
    if !traits.is_empty() {
        let deref_impl = traits
            .iter()
            .find(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_trait_did);
        if let Some(impl_) = deref_impl {
            let has_deref_mut = traits
                .iter()
                .any(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_mut_trait_did);
            render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
        }
        let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
            traits.iter().partition(|t| t.inner_impl().synthetic);
        let (blanket_impl, concrete): (Vec<&&Impl>, _) =
            concrete.into_iter().partition(|t| t.inner_impl().blanket_impl.is_some());
        let mut impls = Buffer::empty_from(&w);
        render_impls(cx, &mut impls, &concrete, containing_item);
        let impls = impls.into_inner();
        if !impls.is_empty() {
            write!(
                w,
                "\
                     Trait Implementations\
                 
\
                 {}",
                impls
            );
        }
        if !synthetic.is_empty() {
            w.write_str(
                "\
                     Auto Trait Implementations\
                     \
                 
\
                 ",
            );
            render_impls(cx, w, &synthetic, containing_item);
            w.write_str("");
        }
        if !blanket_impl.is_empty() {
            w.write_str(
                "\
                     Blanket Implementations\
                     \
                 
\
                 ",
            );
            render_impls(cx, w, &blanket_impl, containing_item);
            w.write_str("");
        }
    }
}
fn render_deref_methods(
    w: &mut Buffer,
    cx: &Context<'_>,
    impl_: &Impl,
    container_item: &clean::Item,
    deref_mut: bool,
) {
    let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
    let (target, real_target) = impl_
        .inner_impl()
        .items
        .iter()
        .find_map(|item| match *item.kind {
            clean::TypedefItem(ref t, true) => Some(match *t {
                clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
                _ => (&t.type_, &t.type_),
            }),
            _ => None,
        })
        .expect("Expected associated type binding");
    debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target);
    let what =
        AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
    if let Some(did) = target.def_id_full(cx.cache()) {
        if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cx.cache()) {
            // `impl Deref for S`
            if did == type_did {
                // Avoid infinite cycles
                return;
            }
        }
        render_assoc_items(w, cx, container_item, did, what);
    } else {
        if let Some(prim) = target.primitive_type() {
            if let Some(&did) = cx.cache.primitive_locations.get(&prim) {
                render_assoc_items(w, cx, container_item, did, what);
            }
        }
    }
}
fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bool {
    let self_type_opt = match *item.kind {
        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, by_value) = match self_ty {
            SelfTy::SelfBorrowed(_, mutability)
            | SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
                (mutability == Mutability::Mut, false, false)
            }
            SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
                (false, Some(did) == cache.owned_box_did, false)
            }
            SelfTy::SelfValue => (false, false, true),
            _ => (false, false, false),
        };
        (deref_mut_ || !by_mut_ref) && !by_box && !by_value
    } else {
        false
    }
}
fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
    let mut out = Buffer::html();
    let mut trait_ = String::new();
    if let Some(did) = decl.output.def_id_full(cx.cache()) {
        if let Some(impls) = cx.cache().impls.get(&did) {
            for i in impls {
                let impl_ = i.inner_impl();
                if impl_.trait_.def_id().map_or(false, |d| {
                    cx.cache().traits.get(&d).map(|t| t.is_notable).unwrap_or(false)
                }) {
                    if out.is_empty() {
                        write!(
                            &mut out,
                            "Notable traits for {}
\
                             ",
                            impl_.for_.print(cx)
                        );
                        trait_.push_str(&impl_.for_.print(cx).to_string());
                    }
                    //use the "where" class here to make it small
                    write!(
                        &mut out,
                        "{}",
                        impl_.print(false, cx)
                    );
                    let t_did = impl_.trait_.def_id_full(cx.cache()).unwrap();
                    for it in &impl_.items {
                        if let clean::TypedefItem(ref tydef, _) = *it.kind {
                            out.push_str("    ");
                            assoc_type(
                                &mut out,
                                it,
                                &[],
                                Some(&tydef.type_),
                                AssocItemLink::GotoSource(t_did.into(), &FxHashSet::default()),
                                "",
                                cx,
                            );
                            out.push_str(";");
                        }
                    }
                }
            }
        }
    }
    if !out.is_empty() {
        out.insert_str(
            0,
            "ⓘ\
            ",
        );
        out.push_str("");
    }
    out.into_inner()
}
fn render_impl(
    w: &mut Buffer,
    cx: &Context<'_>,
    i: &Impl,
    parent: &clean::Item,
    link: AssocItemLink<'_>,
    render_mode: RenderMode,
    outer_version: Option<&str>,
    outer_const_version: Option<&str>,
    show_def_docs: bool,
    use_absolute: Option,
    is_on_foreign_type: bool,
    show_default_items: bool,
    // This argument is used to reference same type with different paths to avoid duplication
    // in documentation pages for trait with automatic implementations like "Send" and "Sync".
    aliases: &[String],
) {
    let cache = cx.cache();
    let traits = &cache.traits;
    let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
    let mut close_tags = String::new();
    // For trait implementations, the `interesting` output contains all methods that have doc
    // comments, and the `boring` output contains all methods that do not. The distinction is
    // used to allow hiding the boring methods.
    fn doc_impl_item(
        boring: &mut Buffer,
        interesting: &mut Buffer,
        cx: &Context<'_>,
        item: &clean::Item,
        parent: &clean::Item,
        link: AssocItemLink<'_>,
        render_mode: RenderMode,
        is_default_item: bool,
        outer_version: Option<&str>,
        outer_const_version: Option<&str>,
        trait_: Option<&clean::Trait>,
        show_def_docs: bool,
    ) {
        let item_type = item.type_();
        let name = item.name.as_ref().unwrap();
        let tcx = cx.tcx();
        let render_method_item = match render_mode {
            RenderMode::Normal => true,
            RenderMode::ForDeref { mut_: deref_mut_ } => {
                should_render_item(&item, deref_mut_, &cx.cache)
            }
        };
        let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
        let mut doc_buffer = Buffer::empty_from(boring);
        let mut info_buffer = Buffer::empty_from(boring);
        let mut short_documented = true;
        if render_method_item {
            if !is_default_item {
                if let Some(t) = trait_ {
                    // The trait item may have been stripped so we might not
                    // find any documentation or stability for it.
                    if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
                        // We need the stability of the item from the trait
                        // because impls can't have a stability.
                        if item.doc_value().is_some() {
                            document_item_info(&mut info_buffer, cx, it, Some(parent));
                            document_full(&mut doc_buffer, item, cx);
                            short_documented = false;
                        } else {
                            // In case the item isn't documented,
                            // provide short documentation from the trait.
                            document_short(&mut doc_buffer, it, cx, link, parent, show_def_docs);
                        }
                    }
                } else {
                    document_item_info(&mut info_buffer, cx, item, Some(parent));
                    if show_def_docs {
                        document_full(&mut doc_buffer, item, cx);
                        short_documented = false;
                    }
                }
            } else {
                document_short(&mut doc_buffer, item, cx, link, parent, show_def_docs);
            }
        }
        let w = if short_documented && trait_.is_some() { interesting } else { boring };
        let toggled = !doc_buffer.is_empty();
        if toggled {
            let method_toggle_class =
                if item_type == ItemType::Method { " method-toggle" } else { "" };
            write!(w, "", method_toggle_class);
        }
        match *item.kind {
            clean::MethodItem(..) | clean::TyMethodItem(_) => {
                // Only render when the method is not static or we allow static methods
                if render_method_item {
                    let id = cx.derive_id(format!("{}.{}", item_type, name));
                    let source_id = trait_
                        .and_then(|trait_| {
                            trait_.items.iter().find(|item| {
                                item.name.map(|n| n.as_str().eq(&name.as_str())).unwrap_or(false)
                            })
                        })
                        .map(|item| format!("{}.{}", item.type_(), name));
                    write!(
                        w,
                        "",
                        id, item_type, in_trait_class,
                    );
                    w.write_str("");
                    render_assoc_item(
                        w,
                        item,
                        link.anchor(source_id.as_ref().unwrap_or(&id)),
                        ItemType::Impl,
                        cx,
                    );
                    w.write_str("");
                    render_stability_since_raw(
                        w,
                        item.stable_since(tcx).as_deref(),
                        item.const_stable_since(tcx).as_deref(),
                        outer_version,
                        outer_const_version,
                    );
                    write!(w, "", id);
                    write_srclink(cx, item, w);
                    w.write_str("");
                }
            }
            clean::TypedefItem(ref tydef, _) => {
                let source_id = format!("{}.{}", ItemType::AssocType, name);
                let id = cx.derive_id(source_id.clone());
                write!(
                    w,
                    "",
                    id, item_type, in_trait_class
                );
                assoc_type(
                    w,
                    item,
                    &Vec::new(),
                    Some(&tydef.type_),
                    link.anchor(if trait_.is_some() { &source_id } else { &id }),
                    "",
                    cx,
                );
                w.write_str("");
                write!(w, "", id);
                w.write_str("");
            }
            clean::AssocConstItem(ref ty, ref default) => {
                let source_id = format!("{}.{}", item_type, name);
                let id = cx.derive_id(source_id.clone());
                write!(
                    w,
                    "",
                    id, item_type, in_trait_class
                );
                assoc_const(
                    w,
                    item,
                    ty,
                    default.as_ref(),
                    link.anchor(if trait_.is_some() { &source_id } else { &id }),
                    "",
                    cx,
                );
                w.write_str("");
                render_stability_since_raw(
                    w,
                    item.stable_since(tcx).as_deref(),
                    item.const_stable_since(tcx).as_deref(),
                    outer_version,
                    outer_const_version,
                );
                write!(w, "", id);
                write_srclink(cx, item, w);
                w.write_str("");
            }
            clean::AssocTypeItem(ref bounds, ref default) => {
                let source_id = format!("{}.{}", item_type, name);
                let id = cx.derive_id(source_id.clone());
                write!(w, "");
            }
            clean::StrippedItem(..) => return,
            _ => panic!("can't make docs for trait item with name {:?}", item.name),
        }
        w.push_buffer(info_buffer);
        if toggled {
            w.write_str("
");
            w.push_buffer(doc_buffer);
            w.push_str("");
        }
    }
    let mut impl_items = Buffer::empty_from(w);
    let mut default_impl_items = Buffer::empty_from(w);
    for trait_item in &i.inner_impl().items {
        doc_impl_item(
            &mut default_impl_items,
            &mut impl_items,
            cx,
            trait_item,
            if trait_.is_some() { &i.impl_item } else { parent },
            link,
            render_mode,
            false,
            outer_version,
            outer_const_version,
            trait_.map(|t| &t.trait_),
            show_def_docs,
        );
    }
    fn render_default_items(
        boring: &mut Buffer,
        interesting: &mut Buffer,
        cx: &Context<'_>,
        t: &clean::Trait,
        i: &clean::Impl,
        parent: &clean::Item,
        render_mode: RenderMode,
        outer_version: Option<&str>,
        outer_const_version: Option<&str>,
        show_def_docs: bool,
    ) {
        for trait_item in &t.items {
            let n = trait_item.name;
            if i.items.iter().any(|m| m.name == n) {
                continue;
            }
            let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap();
            let provided_methods = i.provided_trait_methods(cx.tcx());
            let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
            doc_impl_item(
                boring,
                interesting,
                cx,
                trait_item,
                parent,
                assoc_link,
                render_mode,
                true,
                outer_version,
                outer_const_version,
                Some(t),
                show_def_docs,
            );
        }
    }
    // If we've implemented a trait, then also emit documentation for all
    // default items which weren't overridden in the implementation block.
    // We don't emit documentation for default items if they appear in the
    // Implementations on Foreign Types or Implementors sections.
    if show_default_items {
        if let Some(t) = trait_ {
            render_default_items(
                &mut default_impl_items,
                &mut impl_items,
                cx,
                &t.trait_,
                &i.inner_impl(),
                &i.impl_item,
                render_mode,
                outer_version,
                outer_const_version,
                show_def_docs,
            );
        }
    }
    if render_mode == RenderMode::Normal {
        let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
        if toggled {
            close_tags.insert_str(0, "");
            write!(w, "");
            write!(w, "")
        }
        render_impl_summary(
            w,
            cx,
            i,
            parent,
            outer_version,
            outer_const_version,
            show_def_docs,
            use_absolute,
            is_on_foreign_type,
            aliases,
        );
        if toggled {
            write!(w, "
")
        }
        if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
            let mut ids = cx.id_map.borrow_mut();
            write!(
                w,
                "{}",
                Markdown(
                    &*dox,
                    &i.impl_item.links(cx),
                    &mut ids,
                    cx.shared.codes,
                    cx.shared.edition(),
                    &cx.shared.playground
                )
                .into_string()
            );
        }
    }
    if !default_impl_items.is_empty() || !impl_items.is_empty() {
        w.write_str("");
        w.push_buffer(default_impl_items);
        w.push_buffer(impl_items);
        close_tags.insert_str(0, "");
    }
    w.write_str(&close_tags);
}
pub(crate) fn render_impl_summary(
    w: &mut Buffer,
    cx: &Context<'_>,
    i: &Impl,
    parent: &clean::Item,
    outer_version: Option<&str>,
    outer_const_version: Option<&str>,
    show_def_docs: bool,
    use_absolute: Option,
    is_on_foreign_type: bool,
    // This argument is used to reference same type with different paths to avoid duplication
    // in documentation pages for trait with automatic implementations like "Send" and "Sync".
    aliases: &[String],
) {
    let tcx = cx.tcx();
    let 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)
            } else {
                format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
            }
        }
        None => "impl".to_string(),
    });
    let aliases = if aliases.is_empty() {
        String::new()
    } else {
        format!(" data-aliases=\"{}\"", aliases.join(","))
    };
    if let Some(use_absolute) = use_absolute {
        write!(
            w,
            "\
                     ",
            id, aliases
        );
        write!(w, "{}", i.inner_impl().print(use_absolute, cx));
        if show_def_docs {
            for it in &i.inner_impl().items {
                if let clean::TypedefItem(ref tydef, _) = *it.kind {
                    w.write_str("  ");
                    assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "", cx);
                    w.write_str(";");
                }
            }
        }
        w.write_str("");
    } else {
        write!(
            w,
            "\
                     {}",
            id,
            aliases,
            i.inner_impl().print(false, cx)
        );
    }
    write!(w, "", id);
    write!(w, "");
    render_stability_since_raw(
        w,
        i.impl_item.stable_since(tcx).as_deref(),
        i.impl_item.const_stable_since(tcx).as_deref(),
        outer_version,
        outer_const_version,
    );
    write_srclink(cx, &i.impl_item, w);
    w.write_str(""); // end of "rightside"
    let is_trait = i.inner_impl().trait_.is_some();
    if is_trait {
        if let Some(portability) = portability(&i.impl_item, Some(parent)) {
            write!(w, "{}", portability);
        }
    }
    w.write_str("");
}
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.kind {
                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 {}
\
                 ",
                Escape(version),
            );
        }
    }
    buffer.write_str("");
}
fn get_next_url(used_links: &mut FxHashSet, url: String) -> String {
    if used_links.insert(url.clone()) {
        return url;
    }
    let mut add = 1;
    while !used_links.insert(format!("{}-{}", url, add)) {
        add += 1;
    }
    format!("{}-{}", url, add)
}
fn get_methods(
    i: &clean::Impl,
    for_deref: bool,
    used_links: &mut FxHashSet,
    deref_mut: bool,
    cache: &Cache,
) -> Vec {
    i.items
        .iter()
        .filter_map(|item| match item.name {
            Some(ref name) if !name.is_empty() && item.is_method() => {
                if !for_deref || should_render_item(item, deref_mut, cache) {
                    Some(format!(
                        "{}",
                        get_next_url(used_links, format!("method.{}", name)),
                        name
                    ))
                } else {
                    None
                }
            }
            _ => None,
        })
        .collect::>()
}
// The point is to url encode any potential character from a type with genericity.
fn small_url_encode(s: String) -> String {
    let mut st = String::new();
    let mut last_match = 0;
    for (idx, c) in s.char_indices() {
        let escaped = match c {
            '<' => "%3C",
            '>' => "%3E",
            ' ' => "%20",
            '?' => "%3F",
            '\'' => "%27",
            '&' => "%26",
            ',' => "%2C",
            ':' => "%3A",
            ';' => "%3B",
            '[' => "%5B",
            ']' => "%5D",
            '"' => "%22",
            _ => continue,
        };
        st += &s[last_match..idx];
        st += escaped;
        // NOTE: we only expect single byte characters here - which is fine as long as we
        // only match single byte characters
        last_match = idx + 1;
    }
    if last_match != 0 {
        st += &s[last_match..];
        st
    } else {
        s
    }
}
fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
    let did = it.def_id.expect_real();
    if let Some(v) = cx.cache.impls.get(&did) {
        let mut used_links = FxHashSet::default();
        let cache = cx.cache();
        {
            let used_links_bor = &mut used_links;
            let mut ret = v
                .iter()
                .filter(|i| i.inner_impl().trait_.is_none())
                .flat_map(move |i| {
                    get_methods(i.inner_impl(), false, used_links_bor, false, &cx.cache)
                })
                .collect::>();
            if !ret.is_empty() {
                // We want links' order to be reproducible so we don't use unstable sort.
                ret.sort();
                out.push_str(
                    "Methods\
                     ");
            }
        }
        if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
            let format_impls = |impls: Vec<&Impl>| {
                let mut links = FxHashSet::default();
                let mut ret = impls
                    .iter()
                    .filter_map(|it| {
                        if let Some(ref i) = it.inner_impl().trait_ {
                            let i_display = format!("{:#}", i.print(cx));
                            let out = Escape(&i_display);
                            let encoded = small_url_encode(format!("{:#}", i.print(cx)));
                            let generated = format!(
                                "{}{}",
                                encoded,
                                if it.inner_impl().negative_polarity { "!" } else { "" },
                                out
                            );
                            if links.insert(generated.clone()) { Some(generated) } else { None }
                        } else {
                            None
                        }
                    })
                    .collect::>();
                ret.sort();
                ret
            };
            let write_sidebar_links = |out: &mut Buffer, links: Vec| {
                out.push_str("");
            };
            let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
                v.iter().partition::, _>(|i| i.inner_impl().synthetic);
            let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = concrete
                .into_iter()
                .partition::, _>(|i| i.inner_impl().blanket_impl.is_some());
            let concrete_format = format_impls(concrete);
            let synthetic_format = format_impls(synthetic);
            let blanket_format = format_impls(blanket_impl);
            if !concrete_format.is_empty() {
                out.push_str(
                    "\
                        Trait Implementations",
                );
                write_sidebar_links(out, concrete_format);
            }
            if !synthetic_format.is_empty() {
                out.push_str(
                    "\
                        Auto Trait Implementations",
                );
                write_sidebar_links(out, synthetic_format);
            }
            if !blanket_format.is_empty() {
                out.push_str(
                    "\
                        Blanket Implementations",
                );
                write_sidebar_links(out, blanket_format);
            }
            if let Some(impl_) = v
                .iter()
                .filter(|i| i.inner_impl().trait_.is_some())
                .find(|i| i.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_trait_did)
            {
                sidebar_deref_methods(cx, out, impl_, v);
            }
        }
    }
}
fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec) {
    let c = cx.cache();
    debug!("found Deref: {:?}", impl_);
    if let Some((target, real_target)) =
        impl_.inner_impl().items.iter().find_map(|item| match *item.kind {
            clean::TypedefItem(ref t, true) => Some(match *t {
                clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
                _ => (&t.type_, &t.type_),
            }),
            _ => None,
        })
    {
        debug!("found target, real_target: {:?} {:?}", target, real_target);
        if let Some(did) = target.def_id_full(c) {
            if let Some(type_did) = impl_.inner_impl().for_.def_id_full(c) {
                // `impl Deref for S`
                if did == type_did {
                    // Avoid infinite cycles
                    return;
                }
            }
        }
        let deref_mut = v
            .iter()
            .filter(|i| i.inner_impl().trait_.is_some())
            .any(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_mut_trait_did);
        let inner_impl = target
            .def_id_full(c)
            .or_else(|| {
                target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned())
            })
            .and_then(|did| c.impls.get(&did));
        if let Some(impls) = inner_impl {
            debug!("found inner_impl: {:?}", impls);
            let mut used_links = FxHashSet::default();
            let mut ret = impls
                .iter()
                .filter(|i| i.inner_impl().trait_.is_none())
                .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c))
                .collect::>();
            if !ret.is_empty() {
                write!(
                    out,
                    "Methods from {}<Target={}>",
                    Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
                    Escape(&format!("{:#}", real_target.print(cx))),
                );
                // We want links' order to be reproducible so we don't use unstable sort.
                ret.sort();
                out.push_str("");
            }
        }
        // Recurse into any further impls that might exist for `target`
        if let Some(target_did) = target.def_id_full(c) {
            if let Some(target_impls) = c.impls.get(&target_did) {
                if let Some(target_deref_impl) = target_impls
                    .iter()
                    .filter(|i| i.inner_impl().trait_.is_some())
                    .find(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_trait_did)
                {
                    sidebar_deref_methods(cx, out, target_deref_impl, target_impls);
                }
            }
        }
    }
}
fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) {
    let mut sidebar = Buffer::new();
    let fields = get_struct_fields_name(&s.fields);
    if !fields.is_empty() {
        if let CtorKind::Fictive = s.struct_type {
            sidebar.push_str(
                "Fields\
                ");
        }
    }
    sidebar_assoc_items(cx, &mut sidebar, it);
    if !sidebar.is_empty() {
        write!(buf, "{}", sidebar.into_inner());
    }
}
fn get_id_for_impl_on_foreign_type(
    for_: &clean::Type,
    trait_: &clean::Type,
    cx: &Context<'_>,
) -> String {
    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) => {
            if let Some(ref trait_) = i.trait_ {
                // Alternative format produces no URLs,
                // so this parameter does nothing.
                Some((
                    format!("{:#}", i.for_.print(cx)),
                    get_id_for_impl_on_foreign_type(&i.for_, trait_, cx),
                ))
            } else {
                None
            }
        }
        _ => None,
    }
}
fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
    buf.write_str("");
    fn print_sidebar_section(
        out: &mut Buffer,
        items: &[clean::Item],
        before: &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::>();
        if !items.is_empty() {
            items.sort_unstable();
            out.push_str(before);
            for item in items.into_iter() {
                write(out, &item);
            }
            out.push_str(after);
        }
    }
    print_sidebar_section(
        buf,
        &t.items,
        "\
            Associated Types",
    );
    print_sidebar_section(
        buf,
        &t.items,
        "\
            Associated Constants",
    );
    print_sidebar_section(
        buf,
        &t.items,
        "\
            Required Methods",
    );
    print_sidebar_section(
        buf,
        &t.items,
        "\
            Provided Methods",
    );
    if let Some(implementors) = cx.cache.implementors.get(&it.def_id.expect_real()) {
        let cache = cx.cache();
        let mut res = implementors
            .iter()
            .filter(|i| {
                i.inner_impl()
                    .for_
                    .def_id_full(cache)
                    .map_or(false, |d| !cx.cache.paths.contains_key(&d))
            })
            .filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
            .collect::>();
        if !res.is_empty() {
            res.sort();
            buf.push_str(
                "\
                    Implementations on Foreign Types\
                 ");
        }
    }
    sidebar_assoc_items(cx, buf, it);
    buf.push_str("Implementors");
    if t.is_auto {
        buf.push_str(
            "Auto Implementors",
        );
    }
    buf.push_str("  ")
}
fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
    let mut sidebar = Buffer::new();
    sidebar_assoc_items(cx, &mut sidebar, it);
    if !sidebar.is_empty() {
        write!(buf, "{}", sidebar.into_inner());
    }
}
fn sidebar_typedef(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
    let mut sidebar = Buffer::new();
    sidebar_assoc_items(cx, &mut sidebar, it);
    if !sidebar.is_empty() {
        write!(buf, "{}", sidebar.into_inner());
    }
}
fn get_struct_fields_name(fields: &[clean::Item]) -> Vec {
    let mut fields = fields
        .iter()
        .filter(|f| matches!(*f.kind, clean::StructFieldItem(..)))
        .filter_map(|f| {
            f.name.map(|name| format!("{name}", name = name))
        })
        .collect::>();
    fields.sort();
    fields
}
fn sidebar_union(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, u: &clean::Union) {
    let mut sidebar = Buffer::new();
    let fields = get_struct_fields_name(&u.fields);
    if !fields.is_empty() {
        sidebar.push_str(
            "Fields\
            ");
    }
    sidebar_assoc_items(cx, &mut sidebar, it);
    if !sidebar.is_empty() {
        write!(buf, "{}", sidebar.into_inner());
    }
}
fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) {
    let mut sidebar = Buffer::new();
    let mut variants = e
        .variants
        .iter()
        .filter_map(|v| match v.name {
            Some(ref name) => Some(format!("{name}", name = name)),
            _ => None,
        })
        .collect::>();
    if !variants.is_empty() {
        variants.sort_unstable();
        sidebar.push_str(&format!(
            "Variants\
             ",
            variants.join(""),
        ));
    }
    sidebar_assoc_items(cx, &mut sidebar, it);
    if !sidebar.is_empty() {
        write!(buf, "{}", sidebar.into_inner());
    }
}
fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) {
    match ty {
        ItemType::ExternCrate | ItemType::Import => ("reexports", "Re-exports"),
        ItemType::Module => ("modules", "Modules"),
        ItemType::Struct => ("structs", "Structs"),
        ItemType::Union => ("unions", "Unions"),
        ItemType::Enum => ("enums", "Enums"),
        ItemType::Function => ("functions", "Functions"),
        ItemType::Typedef => ("types", "Type Definitions"),
        ItemType::Static => ("statics", "Statics"),
        ItemType::Constant => ("constants", "Constants"),
        ItemType::Trait => ("traits", "Traits"),
        ItemType::Impl => ("impls", "Implementations"),
        ItemType::TyMethod => ("tymethods", "Type Methods"),
        ItemType::Method => ("methods", "Methods"),
        ItemType::StructField => ("fields", "Struct Fields"),
        ItemType::Variant => ("variants", "Variants"),
        ItemType::Macro => ("macros", "Macros"),
        ItemType::Primitive => ("primitives", "Primitive Types"),
        ItemType::AssocType => ("associated-types", "Associated Types"),
        ItemType::AssocConst => ("associated-consts", "Associated Constants"),
        ItemType::ForeignType => ("foreign-types", "Foreign Types"),
        ItemType::Keyword => ("keywords", "Keywords"),
        ItemType::OpaqueTy => ("opaque-types", "Opaque Types"),
        ItemType::ProcAttribute => ("attributes", "Attribute Macros"),
        ItemType::ProcDerive => ("derives", "Derive Macros"),
        ItemType::TraitAlias => ("trait-aliases", "Trait aliases"),
    }
}
fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
    let mut sidebar = String::new();
    // Re-exports are handled a bit differently because they can be extern crates or imports.
    if items.iter().any(|it| {
        it.name.is_some()
            && (it.type_() == ItemType::ExternCrate
                || (it.type_() == ItemType::Import && !it.is_stripped()))
    }) {
        let (id, name) = item_ty_to_strs(ItemType::Import);
        sidebar.push_str(&format!("{} ", id, name));
    }
    // ordering taken from item_module, reorder, where it prioritized elements in a certain order
    // to print its headings
    for &myty in &[
        ItemType::Primitive,
        ItemType::Module,
        ItemType::Macro,
        ItemType::Struct,
        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::AssocType,
        ItemType::AssocConst,
        ItemType::ForeignType,
        ItemType::Keyword,
    ] {
        if items.iter().any(|it| !it.is_stripped() && it.type_() == myty && it.name.is_some()) {
            let (id, name) = item_ty_to_strs(myty);
            sidebar.push_str(&format!("{} ", id, name));
        }
    }
    if !sidebar.is_empty() {
        write!(buf, "{}
", sidebar);
    }
}
fn sidebar_foreign_type(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
    let mut sidebar = Buffer::new();
    sidebar_assoc_items(cx, &mut sidebar, it);
    if !sidebar.is_empty() {
        write!(buf, "{}", sidebar.into_inner());
    }
}
crate const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang";
/// 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, cache: &Cache) -> Vec {
    let mut out = Vec::new();
    let mut visited = FxHashSet::default();
    let mut work = VecDeque::new();
    work.push_back(first_ty);
    while let Some(ty) = work.pop_front() {
        if !visited.insert(ty.clone()) {
            continue;
        }
        match ty {
            clean::Type::ResolvedPath { did, .. } => {
                let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
                let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
                if let Some(path) = fqp {
                    out.push(path.join("::"));
                }
            }
            clean::Type::Tuple(tys) => {
                work.extend(tys.into_iter());
            }
            clean::Type::Slice(ty) => {
                work.push_back(*ty);
            }
            clean::Type::Array(ty, _) => {
                work.push_back(*ty);
            }
            clean::Type::RawPointer(_, ty) => {
                work.push_back(*ty);
            }
            clean::Type::BorrowedRef { type_, .. } => {
                work.push_back(*type_);
            }
            clean::Type::QPath { self_type, trait_, .. } => {
                work.push_back(*self_type);
                work.push_back(*trait_);
            }
            _ => {}
        }
    }
    out
}