rustdoc/html/render/
mod.rs

1//! Rustdoc's HTML rendering module.
2//!
3//! This modules contains the bulk of the logic necessary for rendering a
4//! rustdoc `clean::Crate` instance to a set of static HTML pages. This
5//! rendering process is largely driven by the `format!` syntax extension to
6//! perform all I/O into files and streams.
7//!
8//! The rendering process is largely driven by the `Context` and `Cache`
9//! structures. The cache is pre-populated by crawling the crate in question,
10//! and then it is shared among the various rendering threads. The cache is meant
11//! to be a fairly large structure not implementing `Clone` (because it's shared
12//! among threads). The context, however, should be a lightweight structure. This
13//! is cloned per-thread and contains information about what is currently being
14//! rendered.
15//!
16//! The main entry point to the rendering system is the implementation of
17//! `FormatRenderer` on `Context`.
18//!
19//! In order to speed up rendering (mostly because of markdown rendering), the
20//! rendering process has been parallelized. This parallelization is only
21//! exposed through the `crate` method on the context, and then also from the
22//! fact that the shared cache is stored in TLS (and must be accessed as such).
23//!
24//! In addition to rendering the crate itself, this module is also responsible
25//! for creating the corresponding search index and source file renderings.
26//! These threads are not parallelized (they haven't been a bottleneck yet), and
27//! both occur before the crate is rendered.
28
29pub(crate) mod search_index;
30
31#[cfg(test)]
32mod tests;
33
34mod context;
35mod ordered_json;
36mod print_item;
37pub(crate) mod sidebar;
38mod sorted_template;
39mod span_map;
40mod type_layout;
41mod write_shared;
42
43use std::borrow::Cow;
44use std::collections::VecDeque;
45use std::fmt::{self, Display as _, Write};
46use std::iter::Peekable;
47use std::path::PathBuf;
48use std::{fs, str};
49
50use askama::Template;
51use itertools::Either;
52use rustc_ast::join_path_syms;
53use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
54use rustc_hir::attrs::{DeprecatedSince, Deprecation};
55use rustc_hir::def_id::{DefId, DefIdSet};
56use rustc_hir::{ConstStability, Mutability, RustcVersion, StabilityLevel, StableSince};
57use rustc_middle::ty::print::PrintTraitRefExt;
58use rustc_middle::ty::{self, TyCtxt};
59use rustc_span::symbol::{Symbol, sym};
60use rustc_span::{BytePos, DUMMY_SP, FileName, RealFileName};
61use serde::ser::SerializeMap;
62use serde::{Serialize, Serializer};
63use tracing::{debug, info};
64
65pub(crate) use self::context::*;
66pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources};
67pub(crate) use self::write_shared::*;
68use crate::clean::{self, ItemId, RenderedLink};
69use crate::display::{Joined as _, MaybeDisplay as _};
70use crate::error::Error;
71use crate::formats::Impl;
72use crate::formats::cache::Cache;
73use crate::formats::item_type::ItemType;
74use crate::html::escape::Escape;
75use crate::html::format::{
76    Ending, HrefError, PrintWithSpace, href, print_abi_with_space, print_constness_with_space,
77    print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space,
78    write_str,
79};
80use crate::html::markdown::{
81    HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
82};
83use crate::html::static_files::SCRAPE_EXAMPLES_HELP_MD;
84use crate::html::{highlight, sources};
85use crate::scrape_examples::{CallData, CallLocation};
86use crate::{DOC_RUST_LANG_ORG_VERSION, try_none};
87
88pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display {
89    fmt::from_fn(move |f| {
90        if !v.ends_with('/') && !v.is_empty() { write!(f, "{v}/") } else { f.write_str(v) }
91    })
92}
93
94/// Specifies whether rendering directly implemented trait items or ones from a certain Deref
95/// impl.
96#[derive(Copy, Clone, Debug)]
97enum AssocItemRender<'a> {
98    All,
99    DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool },
100}
101
102impl AssocItemRender<'_> {
103    fn render_mode(&self) -> RenderMode {
104        match self {
105            Self::All => RenderMode::Normal,
106            &Self::DerefFor { deref_mut_, .. } => RenderMode::ForDeref { mut_: deref_mut_ },
107        }
108    }
109
110    fn class(&self) -> Option<&'static str> {
111        if let Self::DerefFor { .. } = self { Some("impl-items") } else { None }
112    }
113}
114
115/// For different handling of associated items from the Deref target of a type rather than the type
116/// itself.
117#[derive(Copy, Clone, PartialEq)]
118enum RenderMode {
119    Normal,
120    ForDeref { mut_: bool },
121}
122
123// Helper structs for rendering items/sidebars and carrying along contextual
124// information
125
126/// Struct representing one entry in the JS search index. These are all emitted
127/// by hand to a large JS file at the end of cache-creation.
128#[derive(Debug)]
129pub(crate) struct IndexItem {
130    pub(crate) ty: ItemType,
131    pub(crate) defid: Option<DefId>,
132    pub(crate) name: Symbol,
133    pub(crate) path: String,
134    pub(crate) desc: String,
135    pub(crate) parent: Option<DefId>,
136    pub(crate) parent_idx: Option<isize>,
137    pub(crate) exact_path: Option<String>,
138    pub(crate) impl_id: Option<DefId>,
139    pub(crate) search_type: Option<IndexItemFunctionType>,
140    pub(crate) aliases: Box<[Symbol]>,
141    pub(crate) deprecation: Option<Deprecation>,
142}
143
144/// A type used for the search index.
145#[derive(Debug, Eq, PartialEq)]
146struct RenderType {
147    id: Option<RenderTypeId>,
148    generics: Option<Vec<RenderType>>,
149    bindings: Option<Vec<(RenderTypeId, Vec<RenderType>)>>,
150}
151
152impl RenderType {
153    // Types are rendered as lists of lists, because that's pretty compact.
154    // The contents of the lists are always integers in self-terminating hex
155    // form, handled by `RenderTypeId::write_to_string`, so no commas are
156    // needed to separate the items.
157    fn write_to_string(&self, string: &mut String) {
158        fn write_optional_id(id: Option<RenderTypeId>, string: &mut String) {
159            // 0 is a sentinel, everything else is one-indexed
160            match id {
161                Some(id) => id.write_to_string(string),
162                None => string.push('`'),
163            }
164        }
165        // Either just the type id, or `{type, generics, bindings?}`
166        // where generics is a list of types,
167        // and bindings is a list of `{id, typelist}` pairs.
168        if self.generics.is_some() || self.bindings.is_some() {
169            string.push('{');
170            write_optional_id(self.id, string);
171            string.push('{');
172            for generic in self.generics.as_deref().unwrap_or_default() {
173                generic.write_to_string(string);
174            }
175            string.push('}');
176            if self.bindings.is_some() {
177                string.push('{');
178                for binding in self.bindings.as_deref().unwrap_or_default() {
179                    string.push('{');
180                    binding.0.write_to_string(string);
181                    string.push('{');
182                    for constraint in &binding.1[..] {
183                        constraint.write_to_string(string);
184                    }
185                    string.push_str("}}");
186                }
187                string.push('}');
188            }
189            string.push('}');
190        } else {
191            write_optional_id(self.id, string);
192        }
193    }
194}
195
196#[derive(Clone, Copy, Debug, Eq, PartialEq)]
197enum RenderTypeId {
198    DefId(DefId),
199    Primitive(clean::PrimitiveType),
200    AssociatedType(Symbol),
201    Index(isize),
202    Mut,
203}
204
205impl RenderTypeId {
206    fn write_to_string(&self, string: &mut String) {
207        let id: i32 = match &self {
208            // 0 is a sentinel, everything else is one-indexed
209            // concrete type
210            RenderTypeId::Index(idx) if *idx >= 0 => (idx + 1isize).try_into().unwrap(),
211            // generic type parameter
212            RenderTypeId::Index(idx) => (*idx).try_into().unwrap(),
213            _ => panic!("must convert render types to indexes before serializing"),
214        };
215        search_index::encode::write_vlqhex_to_string(id, string);
216    }
217}
218
219/// Full type of functions/methods in the search index.
220#[derive(Debug, Eq, PartialEq)]
221pub(crate) struct IndexItemFunctionType {
222    inputs: Vec<RenderType>,
223    output: Vec<RenderType>,
224    where_clause: Vec<Vec<RenderType>>,
225    param_names: Vec<Option<Symbol>>,
226}
227
228impl IndexItemFunctionType {
229    fn write_to_string<'a>(
230        &'a self,
231        string: &mut String,
232        backref_queue: &mut VecDeque<&'a IndexItemFunctionType>,
233    ) {
234        assert!(backref_queue.len() <= 16);
235        // If we couldn't figure out a type, just write 0,
236        // which is encoded as `` ` `` (see RenderTypeId::write_to_string).
237        let has_missing = self
238            .inputs
239            .iter()
240            .chain(self.output.iter())
241            .any(|i| i.id.is_none() && i.generics.is_none());
242        if has_missing {
243            string.push('`');
244        } else if let Some(idx) = backref_queue.iter().position(|other| *other == self) {
245            // The backref queue has 16 items, so backrefs use
246            // a single hexit, disjoint from the ones used for numbers.
247            string.push(
248                char::try_from('0' as u32 + u32::try_from(idx).unwrap())
249                    .expect("last possible value is '?'"),
250            );
251        } else {
252            backref_queue.push_front(self);
253            if backref_queue.len() > 16 {
254                backref_queue.pop_back();
255            }
256            string.push('{');
257            match &self.inputs[..] {
258                [one] if one.generics.is_none() && one.bindings.is_none() => {
259                    one.write_to_string(string);
260                }
261                _ => {
262                    string.push('{');
263                    for item in &self.inputs[..] {
264                        item.write_to_string(string);
265                    }
266                    string.push('}');
267                }
268            }
269            match &self.output[..] {
270                [] if self.where_clause.is_empty() => {}
271                [one] if one.generics.is_none() && one.bindings.is_none() => {
272                    one.write_to_string(string);
273                }
274                _ => {
275                    string.push('{');
276                    for item in &self.output[..] {
277                        item.write_to_string(string);
278                    }
279                    string.push('}');
280                }
281            }
282            for constraint in &self.where_clause {
283                if let [one] = &constraint[..]
284                    && one.generics.is_none()
285                    && one.bindings.is_none()
286                {
287                    one.write_to_string(string);
288                } else {
289                    string.push('{');
290                    for item in &constraint[..] {
291                        item.write_to_string(string);
292                    }
293                    string.push('}');
294                }
295            }
296            string.push('}');
297        }
298    }
299}
300
301#[derive(Debug, Clone)]
302pub(crate) struct StylePath {
303    /// The path to the theme
304    pub(crate) path: PathBuf,
305}
306
307impl StylePath {
308    pub(crate) fn basename(&self) -> Result<String, Error> {
309        Ok(try_none!(try_none!(self.path.file_stem(), &self.path).to_str(), &self.path).to_string())
310    }
311}
312
313#[derive(Debug, Eq, PartialEq, Hash)]
314struct ItemEntry {
315    url: String,
316    name: String,
317}
318
319impl ItemEntry {
320    fn new(mut url: String, name: String) -> ItemEntry {
321        while url.starts_with('/') {
322            url.remove(0);
323        }
324        ItemEntry { url, name }
325    }
326}
327
328impl ItemEntry {
329    fn print(&self) -> impl fmt::Display {
330        fmt::from_fn(move |f| write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name)))
331    }
332}
333
334impl PartialOrd for ItemEntry {
335    fn partial_cmp(&self, other: &ItemEntry) -> Option<::std::cmp::Ordering> {
336        Some(self.cmp(other))
337    }
338}
339
340impl Ord for ItemEntry {
341    fn cmp(&self, other: &ItemEntry) -> ::std::cmp::Ordering {
342        self.name.cmp(&other.name)
343    }
344}
345
346#[derive(Debug)]
347struct AllTypes {
348    structs: FxIndexSet<ItemEntry>,
349    enums: FxIndexSet<ItemEntry>,
350    unions: FxIndexSet<ItemEntry>,
351    primitives: FxIndexSet<ItemEntry>,
352    traits: FxIndexSet<ItemEntry>,
353    macros: FxIndexSet<ItemEntry>,
354    functions: FxIndexSet<ItemEntry>,
355    type_aliases: FxIndexSet<ItemEntry>,
356    statics: FxIndexSet<ItemEntry>,
357    constants: FxIndexSet<ItemEntry>,
358    attribute_macros: FxIndexSet<ItemEntry>,
359    derive_macros: FxIndexSet<ItemEntry>,
360    trait_aliases: FxIndexSet<ItemEntry>,
361}
362
363impl AllTypes {
364    fn new() -> AllTypes {
365        let new_set = |cap| FxIndexSet::with_capacity_and_hasher(cap, Default::default());
366        AllTypes {
367            structs: new_set(100),
368            enums: new_set(100),
369            unions: new_set(100),
370            primitives: new_set(26),
371            traits: new_set(100),
372            macros: new_set(100),
373            functions: new_set(100),
374            type_aliases: new_set(100),
375            statics: new_set(100),
376            constants: new_set(100),
377            attribute_macros: new_set(100),
378            derive_macros: new_set(100),
379            trait_aliases: new_set(100),
380        }
381    }
382
383    fn append(&mut self, item_name: String, item_type: &ItemType) {
384        let mut url: Vec<_> = item_name.split("::").skip(1).collect();
385        if let Some(name) = url.pop() {
386            let new_url = format!("{}/{item_type}.{name}.html", url.join("/"));
387            url.push(name);
388            let name = url.join("::");
389            match *item_type {
390                ItemType::Struct => self.structs.insert(ItemEntry::new(new_url, name)),
391                ItemType::Enum => self.enums.insert(ItemEntry::new(new_url, name)),
392                ItemType::Union => self.unions.insert(ItemEntry::new(new_url, name)),
393                ItemType::Primitive => self.primitives.insert(ItemEntry::new(new_url, name)),
394                ItemType::Trait => self.traits.insert(ItemEntry::new(new_url, name)),
395                ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)),
396                ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)),
397                ItemType::TypeAlias => self.type_aliases.insert(ItemEntry::new(new_url, name)),
398                ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
399                ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
400                ItemType::ProcAttribute => {
401                    self.attribute_macros.insert(ItemEntry::new(new_url, name))
402                }
403                ItemType::ProcDerive => self.derive_macros.insert(ItemEntry::new(new_url, name)),
404                ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
405                _ => true,
406            };
407        }
408    }
409
410    fn item_sections(&self) -> FxHashSet<ItemSection> {
411        let mut sections = FxHashSet::default();
412
413        if !self.structs.is_empty() {
414            sections.insert(ItemSection::Structs);
415        }
416        if !self.enums.is_empty() {
417            sections.insert(ItemSection::Enums);
418        }
419        if !self.unions.is_empty() {
420            sections.insert(ItemSection::Unions);
421        }
422        if !self.primitives.is_empty() {
423            sections.insert(ItemSection::PrimitiveTypes);
424        }
425        if !self.traits.is_empty() {
426            sections.insert(ItemSection::Traits);
427        }
428        if !self.macros.is_empty() {
429            sections.insert(ItemSection::Macros);
430        }
431        if !self.functions.is_empty() {
432            sections.insert(ItemSection::Functions);
433        }
434        if !self.type_aliases.is_empty() {
435            sections.insert(ItemSection::TypeAliases);
436        }
437        if !self.statics.is_empty() {
438            sections.insert(ItemSection::Statics);
439        }
440        if !self.constants.is_empty() {
441            sections.insert(ItemSection::Constants);
442        }
443        if !self.attribute_macros.is_empty() {
444            sections.insert(ItemSection::AttributeMacros);
445        }
446        if !self.derive_macros.is_empty() {
447            sections.insert(ItemSection::DeriveMacros);
448        }
449        if !self.trait_aliases.is_empty() {
450            sections.insert(ItemSection::TraitAliases);
451        }
452
453        sections
454    }
455
456    fn print(&self) -> impl fmt::Display {
457        fn print_entries(e: &FxIndexSet<ItemEntry>, kind: ItemSection) -> impl fmt::Display {
458            fmt::from_fn(move |f| {
459                if e.is_empty() {
460                    return Ok(());
461                }
462
463                let mut e: Vec<&ItemEntry> = e.iter().collect();
464                e.sort();
465                write!(
466                    f,
467                    "<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">",
468                    id = kind.id(),
469                    title = kind.name(),
470                )?;
471
472                for s in e.iter() {
473                    write!(f, "<li>{}</li>", s.print())?;
474                }
475
476                f.write_str("</ul>")
477            })
478        }
479
480        fmt::from_fn(|f| {
481            f.write_str("<h1>List of all items</h1>")?;
482            // Note: print_entries does not escape the title, because we know the current set of titles
483            // doesn't require escaping.
484            print_entries(&self.structs, ItemSection::Structs).fmt(f)?;
485            print_entries(&self.enums, ItemSection::Enums).fmt(f)?;
486            print_entries(&self.unions, ItemSection::Unions).fmt(f)?;
487            print_entries(&self.primitives, ItemSection::PrimitiveTypes).fmt(f)?;
488            print_entries(&self.traits, ItemSection::Traits).fmt(f)?;
489            print_entries(&self.macros, ItemSection::Macros).fmt(f)?;
490            print_entries(&self.attribute_macros, ItemSection::AttributeMacros).fmt(f)?;
491            print_entries(&self.derive_macros, ItemSection::DeriveMacros).fmt(f)?;
492            print_entries(&self.functions, ItemSection::Functions).fmt(f)?;
493            print_entries(&self.type_aliases, ItemSection::TypeAliases).fmt(f)?;
494            print_entries(&self.trait_aliases, ItemSection::TraitAliases).fmt(f)?;
495            print_entries(&self.statics, ItemSection::Statics).fmt(f)?;
496            print_entries(&self.constants, ItemSection::Constants).fmt(f)?;
497            Ok(())
498        })
499    }
500}
501
502fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
503    let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
504    content.push_str(&format!(
505        "## More information\n\n\
506      If you want more information about this feature, please read the [corresponding chapter in \
507      the Rustdoc book]({DOC_RUST_LANG_ORG_VERSION}/rustdoc/scraped-examples.html)."
508    ));
509
510    format!(
511        "<div class=\"main-heading\">\
512             <h1>About scraped examples</h1>\
513         </div>\
514         <div>{}</div>",
515        fmt::from_fn(|f| Markdown {
516            content: &content,
517            links: &[],
518            ids: &mut IdMap::default(),
519            error_codes: shared.codes,
520            edition: shared.edition(),
521            playground: &shared.playground,
522            heading_offset: HeadingOffset::H1,
523        }
524        .write_into(f))
525    )
526}
527
528fn document(
529    cx: &Context<'_>,
530    item: &clean::Item,
531    parent: Option<&clean::Item>,
532    heading_offset: HeadingOffset,
533) -> impl fmt::Display {
534    if let Some(ref name) = item.name {
535        info!("Documenting {name}");
536    }
537
538    fmt::from_fn(move |f| {
539        document_item_info(cx, item, parent).render_into(f)?;
540        if parent.is_none() {
541            write!(f, "{}", document_full_collapsible(item, cx, heading_offset))
542        } else {
543            write!(f, "{}", document_full(item, cx, heading_offset))
544        }
545    })
546}
547
548/// Render md_text as markdown.
549fn render_markdown(
550    cx: &Context<'_>,
551    md_text: &str,
552    links: Vec<RenderedLink>,
553    heading_offset: HeadingOffset,
554) -> impl fmt::Display {
555    fmt::from_fn(move |f| {
556        f.write_str("<div class=\"docblock\">")?;
557        Markdown {
558            content: md_text,
559            links: &links,
560            ids: &mut cx.id_map.borrow_mut(),
561            error_codes: cx.shared.codes,
562            edition: cx.shared.edition(),
563            playground: &cx.shared.playground,
564            heading_offset,
565        }
566        .write_into(&mut *f)?;
567        f.write_str("</div>")
568    })
569}
570
571/// Writes a documentation block containing only the first paragraph of the documentation. If the
572/// docs are longer, a "Read more" link is appended to the end.
573fn document_short(
574    item: &clean::Item,
575    cx: &Context<'_>,
576    link: AssocItemLink<'_>,
577    parent: &clean::Item,
578    show_def_docs: bool,
579) -> impl fmt::Display {
580    fmt::from_fn(move |f| {
581        document_item_info(cx, item, Some(parent)).render_into(f)?;
582        if !show_def_docs {
583            return Ok(());
584        }
585        let s = item.doc_value();
586        if !s.is_empty() {
587            let (mut summary_html, has_more_content) =
588                MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content();
589
590            let link = if has_more_content {
591                let link = fmt::from_fn(|f| {
592                    write!(
593                        f,
594                        " <a{}>Read more</a>",
595                        assoc_href_attr(item, link, cx).maybe_display()
596                    )
597                });
598
599                if let Some(idx) = summary_html.rfind("</p>") {
600                    summary_html.insert_str(idx, &link.to_string());
601                    None
602                } else {
603                    Some(link)
604                }
605            } else {
606                None
607            }
608            .maybe_display();
609
610            write!(f, "<div class='docblock'>{summary_html}{link}</div>")?;
611        }
612        Ok(())
613    })
614}
615
616fn document_full_collapsible(
617    item: &clean::Item,
618    cx: &Context<'_>,
619    heading_offset: HeadingOffset,
620) -> impl fmt::Display {
621    document_full_inner(item, cx, true, heading_offset)
622}
623
624fn document_full(
625    item: &clean::Item,
626    cx: &Context<'_>,
627    heading_offset: HeadingOffset,
628) -> impl fmt::Display {
629    document_full_inner(item, cx, false, heading_offset)
630}
631
632fn document_full_inner(
633    item: &clean::Item,
634    cx: &Context<'_>,
635    is_collapsible: bool,
636    heading_offset: HeadingOffset,
637) -> impl fmt::Display {
638    fmt::from_fn(move |f| {
639        if let Some(s) = item.opt_doc_value() {
640            debug!("Doc block: =====\n{s}\n=====");
641            if is_collapsible {
642                write!(
643                    f,
644                    "<details class=\"toggle top-doc\" open>\
645                     <summary class=\"hideme\">\
646                        <span>Expand description</span>\
647                     </summary>{}</details>",
648                    render_markdown(cx, &s, item.links(cx), heading_offset)
649                )?;
650            } else {
651                write!(f, "{}", render_markdown(cx, &s, item.links(cx), heading_offset))?;
652            }
653        }
654
655        let kind = match &item.kind {
656            clean::ItemKind::StrippedItem(box kind) | kind => kind,
657        };
658
659        if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind {
660            render_call_locations(f, cx, item)?;
661        }
662        Ok(())
663    })
664}
665
666#[derive(Template)]
667#[template(path = "item_info.html")]
668struct ItemInfo {
669    items: Vec<ShortItemInfo>,
670}
671/// Add extra information about an item such as:
672///
673/// * Stability
674/// * Deprecated
675/// * Required features (through the `doc_cfg` feature)
676fn document_item_info(
677    cx: &Context<'_>,
678    item: &clean::Item,
679    parent: Option<&clean::Item>,
680) -> ItemInfo {
681    let items = short_item_info(item, cx, parent);
682    ItemInfo { items }
683}
684
685fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<String> {
686    let cfg = match (&item.cfg, parent.and_then(|p| p.cfg.as_ref())) {
687        (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
688        (cfg, _) => cfg.as_deref().cloned(),
689    };
690
691    debug!(
692        "Portability {name:?} {item_cfg:?} (parent: {parent:?}) - {parent_cfg:?} = {cfg:?}",
693        name = item.name,
694        item_cfg = item.cfg,
695        parent_cfg = parent.and_then(|p| p.cfg.as_ref()),
696    );
697
698    Some(cfg?.render_long_html())
699}
700
701#[derive(Template)]
702#[template(path = "short_item_info.html")]
703enum ShortItemInfo {
704    /// A message describing the deprecation of this item
705    Deprecation {
706        message: String,
707    },
708    /// The feature corresponding to an unstable item, and optionally
709    /// a tracking issue URL and number.
710    Unstable {
711        feature: String,
712        tracking: Option<(String, u32)>,
713    },
714    Portability {
715        message: String,
716    },
717}
718
719/// Render the stability, deprecation and portability information that is displayed at the top of
720/// the item's documentation.
721fn short_item_info(
722    item: &clean::Item,
723    cx: &Context<'_>,
724    parent: Option<&clean::Item>,
725) -> Vec<ShortItemInfo> {
726    let mut extra_info = vec![];
727
728    if let Some(depr @ Deprecation { note, since, suggestion: _ }) = item.deprecation(cx.tcx()) {
729        // We display deprecation messages for #[deprecated], but only display
730        // the future-deprecation messages for rustc versions.
731        let mut message = match since {
732            DeprecatedSince::RustcVersion(version) => {
733                if depr.is_in_effect() {
734                    format!("Deprecated since {version}")
735                } else {
736                    format!("Deprecating in {version}")
737                }
738            }
739            DeprecatedSince::Future => String::from("Deprecating in a future version"),
740            DeprecatedSince::NonStandard(since) => {
741                format!("Deprecated since {}", Escape(since.as_str()))
742            }
743            DeprecatedSince::Unspecified | DeprecatedSince::Err => String::from("Deprecated"),
744        };
745
746        if let Some(note) = note {
747            let note = note.as_str();
748            let mut id_map = cx.id_map.borrow_mut();
749            let html = MarkdownItemInfo(note, &mut id_map);
750            message.push_str(": ");
751            html.write_into(&mut message).unwrap();
752        }
753        extra_info.push(ShortItemInfo::Deprecation { message });
754    }
755
756    // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
757    // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
758    if let Some((StabilityLevel::Unstable { reason: _, issue, .. }, feature)) = item
759        .stability(cx.tcx())
760        .as_ref()
761        .filter(|stab| stab.feature != sym::rustc_private)
762        .map(|stab| (stab.level, stab.feature))
763    {
764        let tracking = if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue)
765        {
766            Some((url.clone(), issue.get()))
767        } else {
768            None
769        };
770        extra_info.push(ShortItemInfo::Unstable { feature: feature.to_string(), tracking });
771    }
772
773    if let Some(message) = portability(item, parent) {
774        extra_info.push(ShortItemInfo::Portability { message });
775    }
776
777    extra_info
778}
779
780// Render the list of items inside one of the sections "Trait Implementations",
781// "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
782fn render_impls(
783    cx: &Context<'_>,
784    mut w: impl Write,
785    impls: &[&Impl],
786    containing_item: &clean::Item,
787    toggle_open_by_default: bool,
788) {
789    let mut rendered_impls = impls
790        .iter()
791        .map(|i| {
792            let did = i.trait_did().unwrap();
793            let provided_trait_methods = i.inner_impl().provided_trait_methods(cx.tcx());
794            let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
795            let imp = render_impl(
796                cx,
797                i,
798                containing_item,
799                assoc_link,
800                RenderMode::Normal,
801                None,
802                &[],
803                ImplRenderingParameters {
804                    show_def_docs: true,
805                    show_default_items: true,
806                    show_non_assoc_items: true,
807                    toggle_open_by_default,
808                },
809            );
810            imp.to_string()
811        })
812        .collect::<Vec<_>>();
813    rendered_impls.sort();
814    w.write_str(&rendered_impls.join("")).unwrap();
815}
816
817/// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
818fn assoc_href_attr(
819    it: &clean::Item,
820    link: AssocItemLink<'_>,
821    cx: &Context<'_>,
822) -> Option<impl fmt::Display> {
823    let name = it.name.unwrap();
824    let item_type = it.type_();
825
826    enum Href<'a> {
827        AnchorId(&'a str),
828        Anchor(ItemType),
829        Url(String, ItemType),
830    }
831
832    let href = match link {
833        AssocItemLink::Anchor(Some(id)) => Href::AnchorId(id),
834        AssocItemLink::Anchor(None) => Href::Anchor(item_type),
835        AssocItemLink::GotoSource(did, provided_methods) => {
836            // We're creating a link from the implementation of an associated item to its
837            // declaration in the trait declaration.
838            let item_type = match item_type {
839                // For historical but not technical reasons, the item type of methods in
840                // trait declarations depends on whether the method is required (`TyMethod`) or
841                // provided (`Method`).
842                ItemType::Method | ItemType::TyMethod => {
843                    if provided_methods.contains(&name) {
844                        ItemType::Method
845                    } else {
846                        ItemType::TyMethod
847                    }
848                }
849                // For associated types and constants, no such distinction exists.
850                item_type => item_type,
851            };
852
853            match href(did.expect_def_id(), cx) {
854                Ok((url, ..)) => Href::Url(url, item_type),
855                // The link is broken since it points to an external crate that wasn't documented.
856                // Do not create any link in such case. This is better than falling back to a
857                // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
858                // (that used to happen in older versions). Indeed, in most cases this dummy would
859                // coincide with the `id`. However, it would not always do so.
860                // In general, this dummy would be incorrect:
861                // If the type with the trait impl also had an inherent impl with an assoc. item of
862                // the *same* name as this impl item, the dummy would link to that one even though
863                // those two items are distinct!
864                // In this scenario, the actual `id` of this impl item would be
865                // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
866                Err(HrefError::DocumentationNotBuilt) => return None,
867                Err(_) => Href::Anchor(item_type),
868            }
869        }
870    };
871
872    let href = fmt::from_fn(move |f| match &href {
873        Href::AnchorId(id) => write!(f, "#{id}"),
874        Href::Url(url, item_type) => {
875            write!(f, "{url}#{item_type}.{name}")
876        }
877        Href::Anchor(item_type) => {
878            write!(f, "#{item_type}.{name}")
879        }
880    });
881
882    // If there is no `href` for the reason explained above, simply do not render it which is valid:
883    // https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
884    Some(fmt::from_fn(move |f| write!(f, " href=\"{href}\"")))
885}
886
887#[derive(Debug)]
888enum AssocConstValue<'a> {
889    // In trait definitions, it is relevant for the public API whether an
890    // associated constant comes with a default value, so even if we cannot
891    // render its value, the presence of a value must be shown using `= _`.
892    TraitDefault(&'a clean::ConstantKind),
893    // In impls, there is no need to show `= _`.
894    Impl(&'a clean::ConstantKind),
895    None,
896}
897
898fn assoc_const(
899    it: &clean::Item,
900    generics: &clean::Generics,
901    ty: &clean::Type,
902    value: AssocConstValue<'_>,
903    link: AssocItemLink<'_>,
904    indent: usize,
905    cx: &Context<'_>,
906) -> impl fmt::Display {
907    let tcx = cx.tcx();
908    fmt::from_fn(move |w| {
909        write!(
910            w,
911            "{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
912            indent = " ".repeat(indent),
913            vis = visibility_print_with_space(it, cx),
914            href = assoc_href_attr(it, link, cx).maybe_display(),
915            name = it.name.as_ref().unwrap(),
916            generics = generics.print(cx),
917            ty = ty.print(cx),
918        )?;
919        if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value {
920            // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
921            //        hood which adds noisy underscores and a type suffix to number literals.
922            //        This hurts readability in this context especially when more complex expressions
923            //        are involved and it doesn't add much of value.
924            //        Find a way to print constants here without all that jazz.
925            let repr = konst.value(tcx).unwrap_or_else(|| konst.expr(tcx));
926            if match value {
927                AssocConstValue::TraitDefault(_) => true, // always show
928                AssocConstValue::Impl(_) => repr != "_", // show if there is a meaningful value to show
929                AssocConstValue::None => unreachable!(),
930            } {
931                write!(w, " = {}", Escape(&repr))?;
932            }
933        }
934        write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline).maybe_display())
935    })
936}
937
938fn assoc_type(
939    it: &clean::Item,
940    generics: &clean::Generics,
941    bounds: &[clean::GenericBound],
942    default: Option<&clean::Type>,
943    link: AssocItemLink<'_>,
944    indent: usize,
945    cx: &Context<'_>,
946) -> impl fmt::Display {
947    fmt::from_fn(move |w| {
948        write!(
949            w,
950            "{indent}{vis}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
951            indent = " ".repeat(indent),
952            vis = visibility_print_with_space(it, cx),
953            href = assoc_href_attr(it, link, cx).maybe_display(),
954            name = it.name.as_ref().unwrap(),
955            generics = generics.print(cx),
956        )?;
957        if !bounds.is_empty() {
958            write!(w, ": {}", print_generic_bounds(bounds, cx))?;
959        }
960        // Render the default before the where-clause which aligns with the new recommended style. See #89122.
961        if let Some(default) = default {
962            write!(w, " = {}", default.print(cx))?;
963        }
964        write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline).maybe_display())
965    })
966}
967
968fn assoc_method(
969    meth: &clean::Item,
970    g: &clean::Generics,
971    d: &clean::FnDecl,
972    link: AssocItemLink<'_>,
973    parent: ItemType,
974    cx: &Context<'_>,
975    render_mode: RenderMode,
976) -> impl fmt::Display {
977    let tcx = cx.tcx();
978    let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
979    let name = meth.name.as_ref().unwrap();
980    let vis = visibility_print_with_space(meth, cx).to_string();
981    let defaultness = print_default_space(meth.is_default());
982    // FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
983    // this condition.
984    let constness = match render_mode {
985        RenderMode::Normal => print_constness_with_space(
986            &header.constness,
987            meth.stable_since(tcx),
988            meth.const_stability(tcx),
989        ),
990        RenderMode::ForDeref { .. } => "",
991    };
992
993    fmt::from_fn(move |w| {
994        let asyncness = header.asyncness.print_with_space();
995        let safety = header.safety.print_with_space();
996        let abi = print_abi_with_space(header.abi).to_string();
997        let href = assoc_href_attr(meth, link, cx).maybe_display();
998
999        // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
1000        let generics_len = format!("{:#}", g.print(cx)).len();
1001        let mut header_len = "fn ".len()
1002            + vis.len()
1003            + defaultness.len()
1004            + constness.len()
1005            + asyncness.len()
1006            + safety.len()
1007            + abi.len()
1008            + name.as_str().len()
1009            + generics_len;
1010
1011        let notable_traits = notable_traits_button(&d.output, cx).maybe_display();
1012
1013        let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
1014            header_len += 4;
1015            let indent_str = "    ";
1016            write!(w, "{}", render_attributes_in_pre(meth, indent_str, cx))?;
1017            (4, indent_str, Ending::NoNewline)
1018        } else {
1019            render_attributes_in_code(w, meth, cx);
1020            (0, "", Ending::Newline)
1021        };
1022        write!(
1023            w,
1024            "{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \
1025            <a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}",
1026            indent = indent_str,
1027            generics = g.print(cx),
1028            decl = d.full_print(header_len, indent, cx),
1029            where_clause = print_where_clause(g, cx, indent, end_newline).maybe_display(),
1030        )
1031    })
1032}
1033
1034/// Writes a span containing the versions at which an item became stable and/or const-stable. For
1035/// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would
1036/// write a span containing "1.0.0 (const: 1.45.0)".
1037///
1038/// Returns `None` if there is no stability annotation to be rendered.
1039///
1040/// Stability and const-stability are considered separately. If the item is unstable, no version
1041/// will be written. If the item is const-unstable, "const: unstable" will be appended to the
1042/// span, with a link to the tracking issue if present. If an item's stability or const-stability
1043/// version matches the version of its enclosing item, that version will be omitted.
1044///
1045/// Note that it is possible for an unstable function to be const-stable. In that case, the span
1046/// will include the const-stable version, but no stable version will be emitted, as a natural
1047/// consequence of the above rules.
1048fn render_stability_since_raw_with_extra(
1049    stable_version: Option<StableSince>,
1050    const_stability: Option<ConstStability>,
1051    extra_class: &str,
1052) -> Option<impl fmt::Display> {
1053    let mut title = String::new();
1054    let mut stability = String::new();
1055
1056    if let Some(version) = stable_version.and_then(|version| since_to_string(&version)) {
1057        stability.push_str(&version);
1058        title.push_str(&format!("Stable since Rust version {version}"));
1059    }
1060
1061    let const_title_and_stability = match const_stability {
1062        Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. }) => {
1063            since_to_string(&since)
1064                .map(|since| (format!("const since {since}"), format!("const: {since}")))
1065        }
1066        Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
1067            if stable_version.is_none() {
1068                // don't display const unstable if entirely unstable
1069                None
1070            } else {
1071                let unstable = if let Some(n) = issue {
1072                    format!(
1073                        "<a \
1074                        href=\"https://github.com/rust-lang/rust/issues/{n}\" \
1075                        title=\"Tracking issue for {feature}\"\
1076                       >unstable</a>"
1077                    )
1078                } else {
1079                    String::from("unstable")
1080                };
1081
1082                Some((String::from("const unstable"), format!("const: {unstable}")))
1083            }
1084        }
1085        _ => None,
1086    };
1087
1088    if let Some((const_title, const_stability)) = const_title_and_stability {
1089        if !title.is_empty() {
1090            title.push_str(&format!(", {const_title}"));
1091        } else {
1092            title.push_str(&const_title);
1093        }
1094
1095        if !stability.is_empty() {
1096            stability.push_str(&format!(" ({const_stability})"));
1097        } else {
1098            stability.push_str(&const_stability);
1099        }
1100    }
1101
1102    (!stability.is_empty()).then_some(fmt::from_fn(move |w| {
1103        write!(w, r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#)
1104    }))
1105}
1106
1107fn since_to_string(since: &StableSince) -> Option<String> {
1108    match since {
1109        StableSince::Version(since) => Some(since.to_string()),
1110        StableSince::Current => Some(RustcVersion::CURRENT.to_string()),
1111        StableSince::Err(_) => None,
1112    }
1113}
1114
1115#[inline]
1116fn render_stability_since_raw(
1117    ver: Option<StableSince>,
1118    const_stability: Option<ConstStability>,
1119) -> Option<impl fmt::Display> {
1120    render_stability_since_raw_with_extra(ver, const_stability, "")
1121}
1122
1123fn render_assoc_item(
1124    item: &clean::Item,
1125    link: AssocItemLink<'_>,
1126    parent: ItemType,
1127    cx: &Context<'_>,
1128    render_mode: RenderMode,
1129) -> impl fmt::Display {
1130    fmt::from_fn(move |f| match &item.kind {
1131        clean::StrippedItem(..) => Ok(()),
1132        clean::RequiredMethodItem(m) | clean::MethodItem(m, _) => {
1133            assoc_method(item, &m.generics, &m.decl, link, parent, cx, render_mode).fmt(f)
1134        }
1135        clean::RequiredAssocConstItem(generics, ty) => assoc_const(
1136            item,
1137            generics,
1138            ty,
1139            AssocConstValue::None,
1140            link,
1141            if parent == ItemType::Trait { 4 } else { 0 },
1142            cx,
1143        )
1144        .fmt(f),
1145        clean::ProvidedAssocConstItem(ci) => assoc_const(
1146            item,
1147            &ci.generics,
1148            &ci.type_,
1149            AssocConstValue::TraitDefault(&ci.kind),
1150            link,
1151            if parent == ItemType::Trait { 4 } else { 0 },
1152            cx,
1153        )
1154        .fmt(f),
1155        clean::ImplAssocConstItem(ci) => assoc_const(
1156            item,
1157            &ci.generics,
1158            &ci.type_,
1159            AssocConstValue::Impl(&ci.kind),
1160            link,
1161            if parent == ItemType::Trait { 4 } else { 0 },
1162            cx,
1163        )
1164        .fmt(f),
1165        clean::RequiredAssocTypeItem(generics, bounds) => assoc_type(
1166            item,
1167            generics,
1168            bounds,
1169            None,
1170            link,
1171            if parent == ItemType::Trait { 4 } else { 0 },
1172            cx,
1173        )
1174        .fmt(f),
1175        clean::AssocTypeItem(ty, bounds) => assoc_type(
1176            item,
1177            &ty.generics,
1178            bounds,
1179            Some(ty.item_type.as_ref().unwrap_or(&ty.type_)),
1180            link,
1181            if parent == ItemType::Trait { 4 } else { 0 },
1182            cx,
1183        )
1184        .fmt(f),
1185        _ => panic!("render_assoc_item called on non-associated-item"),
1186    })
1187}
1188
1189// When an attribute is rendered inside a `<pre>` tag, it is formatted using
1190// a whitespace prefix and newline.
1191fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display {
1192    fmt::from_fn(move |f| {
1193        for a in it.attributes(cx.tcx(), cx.cache()) {
1194            writeln!(f, "{prefix}{a}")?;
1195        }
1196        Ok(())
1197    })
1198}
1199
1200struct CodeAttribute(String);
1201
1202fn render_code_attribute(code_attr: CodeAttribute, w: &mut impl fmt::Write) {
1203    write!(w, "<div class=\"code-attribute\">{}</div>", code_attr.0).unwrap();
1204}
1205
1206// When an attribute is rendered inside a <code> tag, it is formatted using
1207// a div to produce a newline after it.
1208fn render_attributes_in_code(w: &mut impl fmt::Write, it: &clean::Item, cx: &Context<'_>) {
1209    for attr in it.attributes(cx.tcx(), cx.cache()) {
1210        render_code_attribute(CodeAttribute(attr), w);
1211    }
1212}
1213
1214/// used for type aliases to only render their `repr` attribute.
1215fn render_repr_attributes_in_code(
1216    w: &mut impl fmt::Write,
1217    cx: &Context<'_>,
1218    def_id: DefId,
1219    item_type: ItemType,
1220) {
1221    if let Some(repr) = clean::repr_attributes(cx.tcx(), cx.cache(), def_id, item_type) {
1222        render_code_attribute(CodeAttribute(repr), w);
1223    }
1224}
1225
1226#[derive(Copy, Clone)]
1227enum AssocItemLink<'a> {
1228    Anchor(Option<&'a str>),
1229    GotoSource(ItemId, &'a FxIndexSet<Symbol>),
1230}
1231
1232impl<'a> AssocItemLink<'a> {
1233    fn anchor(&self, id: &'a str) -> Self {
1234        match *self {
1235            AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(id)),
1236            ref other => *other,
1237        }
1238    }
1239}
1240
1241fn write_section_heading(
1242    title: impl fmt::Display,
1243    id: &str,
1244    extra_class: Option<&str>,
1245    extra: impl fmt::Display,
1246) -> impl fmt::Display {
1247    fmt::from_fn(move |w| {
1248        let (extra_class, whitespace) = match extra_class {
1249            Some(extra) => (extra, " "),
1250            None => ("", ""),
1251        };
1252        write!(
1253            w,
1254            "<h2 id=\"{id}\" class=\"{extra_class}{whitespace}section-header\">\
1255            {title}\
1256            <a href=\"#{id}\" class=\"anchor\">§</a>\
1257         </h2>{extra}",
1258        )
1259    })
1260}
1261
1262fn write_impl_section_heading(title: impl fmt::Display, id: &str) -> impl fmt::Display {
1263    write_section_heading(title, id, None, "")
1264}
1265
1266fn render_all_impls(
1267    mut w: impl Write,
1268    cx: &Context<'_>,
1269    containing_item: &clean::Item,
1270    concrete: &[&Impl],
1271    synthetic: &[&Impl],
1272    blanket_impl: &[&Impl],
1273) {
1274    let impls = {
1275        let mut buf = String::new();
1276        render_impls(cx, &mut buf, concrete, containing_item, true);
1277        buf
1278    };
1279    if !impls.is_empty() {
1280        write!(
1281            w,
1282            "{}<div id=\"trait-implementations-list\">{impls}</div>",
1283            write_impl_section_heading("Trait Implementations", "trait-implementations")
1284        )
1285        .unwrap();
1286    }
1287
1288    if !synthetic.is_empty() {
1289        write!(
1290            w,
1291            "{}<div id=\"synthetic-implementations-list\">",
1292            write_impl_section_heading("Auto Trait Implementations", "synthetic-implementations",)
1293        )
1294        .unwrap();
1295        render_impls(cx, &mut w, synthetic, containing_item, false);
1296        w.write_str("</div>").unwrap();
1297    }
1298
1299    if !blanket_impl.is_empty() {
1300        write!(
1301            w,
1302            "{}<div id=\"blanket-implementations-list\">",
1303            write_impl_section_heading("Blanket Implementations", "blanket-implementations")
1304        )
1305        .unwrap();
1306        render_impls(cx, &mut w, blanket_impl, containing_item, false);
1307        w.write_str("</div>").unwrap();
1308    }
1309}
1310
1311fn render_assoc_items(
1312    cx: &Context<'_>,
1313    containing_item: &clean::Item,
1314    it: DefId,
1315    what: AssocItemRender<'_>,
1316) -> impl fmt::Display {
1317    fmt::from_fn(move |f| {
1318        let mut derefs = DefIdSet::default();
1319        derefs.insert(it);
1320        render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs);
1321        Ok(())
1322    })
1323}
1324
1325fn render_assoc_items_inner(
1326    mut w: &mut dyn fmt::Write,
1327    cx: &Context<'_>,
1328    containing_item: &clean::Item,
1329    it: DefId,
1330    what: AssocItemRender<'_>,
1331    derefs: &mut DefIdSet,
1332) {
1333    info!("Documenting associated items of {:?}", containing_item.name);
1334    let cache = &cx.shared.cache;
1335    let Some(v) = cache.impls.get(&it) else { return };
1336    let (mut non_trait, traits): (Vec<_>, _) =
1337        v.iter().partition(|i| i.inner_impl().trait_.is_none());
1338    if !non_trait.is_empty() {
1339        let render_mode = what.render_mode();
1340        let class_html = what
1341            .class()
1342            .map(|class| fmt::from_fn(move |f| write!(f, r#" class="{class}""#)))
1343            .maybe_display();
1344        let (section_heading, id) = match what {
1345            AssocItemRender::All => (
1346                Either::Left(write_impl_section_heading("Implementations", "implementations")),
1347                Cow::Borrowed("implementations-list"),
1348            ),
1349            AssocItemRender::DerefFor { trait_, type_, .. } => {
1350                let id =
1351                    cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
1352                // the `impls.get` above only looks at the outermost type,
1353                // and the Deref impl may only be implemented for certain
1354                // values of generic parameters.
1355                // for example, if an item impls `Deref<[u8]>`,
1356                // we should not show methods from `[MaybeUninit<u8>]`.
1357                // this `retain` filters out any instances where
1358                // the types do not line up perfectly.
1359                non_trait.retain(|impl_| {
1360                    type_.is_doc_subtype_of(&impl_.inner_impl().for_, &cx.shared.cache)
1361                });
1362                let derived_id = cx.derive_id(&id);
1363                if let Some(def_id) = type_.def_id(cx.cache()) {
1364                    cx.deref_id_map.borrow_mut().insert(def_id, id.clone());
1365                }
1366                (
1367                    Either::Right(fmt::from_fn(move |f| {
1368                        write!(
1369                            f,
1370                            "<details class=\"toggle big-toggle\" open><summary>{}</summary>",
1371                            write_impl_section_heading(
1372                                fmt::from_fn(|f| write!(
1373                                    f,
1374                                    "<span>Methods from {trait_}&lt;Target = {type_}&gt;</span>",
1375                                    trait_ = trait_.print(cx),
1376                                    type_ = type_.print(cx),
1377                                )),
1378                                &id,
1379                            )
1380                        )
1381                    })),
1382                    Cow::Owned(derived_id),
1383                )
1384            }
1385        };
1386        let mut impls_buf = String::new();
1387        for i in &non_trait {
1388            write_str(
1389                &mut impls_buf,
1390                format_args!(
1391                    "{}",
1392                    render_impl(
1393                        cx,
1394                        i,
1395                        containing_item,
1396                        AssocItemLink::Anchor(None),
1397                        render_mode,
1398                        None,
1399                        &[],
1400                        ImplRenderingParameters {
1401                            show_def_docs: true,
1402                            show_default_items: true,
1403                            show_non_assoc_items: true,
1404                            toggle_open_by_default: true,
1405                        },
1406                    )
1407                ),
1408            );
1409        }
1410        if !impls_buf.is_empty() {
1411            write!(
1412                w,
1413                "{section_heading}<div id=\"{id}\"{class_html}>{impls_buf}</div>{}",
1414                matches!(what, AssocItemRender::DerefFor { .. })
1415                    .then_some("</details>")
1416                    .maybe_display(),
1417            )
1418            .unwrap();
1419        }
1420    }
1421
1422    if !traits.is_empty() {
1423        let deref_impl =
1424            traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait());
1425        if let Some(impl_) = deref_impl {
1426            let has_deref_mut =
1427                traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
1428            render_deref_methods(&mut w, cx, impl_, containing_item, has_deref_mut, derefs);
1429        }
1430
1431        // If we were already one level into rendering deref methods, we don't want to render
1432        // anything after recursing into any further deref methods above.
1433        if let AssocItemRender::DerefFor { .. } = what {
1434            return;
1435        }
1436
1437        let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
1438            traits.into_iter().partition(|t| t.inner_impl().kind.is_auto());
1439        let (blanket_impl, concrete): (Vec<&Impl>, _) =
1440            concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
1441
1442        render_all_impls(w, cx, containing_item, &concrete, &synthetic, &blanket_impl);
1443    }
1444}
1445
1446/// `derefs` is the set of all deref targets that have already been handled.
1447fn render_deref_methods(
1448    mut w: impl Write,
1449    cx: &Context<'_>,
1450    impl_: &Impl,
1451    container_item: &clean::Item,
1452    deref_mut: bool,
1453    derefs: &mut DefIdSet,
1454) {
1455    let cache = cx.cache();
1456    let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
1457    let (target, real_target) = impl_
1458        .inner_impl()
1459        .items
1460        .iter()
1461        .find_map(|item| match item.kind {
1462            clean::AssocTypeItem(box ref t, _) => Some(match *t {
1463                clean::TypeAlias { item_type: Some(ref type_), .. } => (type_, &t.type_),
1464                _ => (&t.type_, &t.type_),
1465            }),
1466            _ => None,
1467        })
1468        .expect("Expected associated type binding");
1469    debug!(
1470        "Render deref methods for {for_:#?}, target {target:#?}",
1471        for_ = impl_.inner_impl().for_
1472    );
1473    let what =
1474        AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
1475    if let Some(did) = target.def_id(cache) {
1476        if let Some(type_did) = impl_.inner_impl().for_.def_id(cache) {
1477            // `impl Deref<Target = S> for S`
1478            if did == type_did || !derefs.insert(did) {
1479                // Avoid infinite cycles
1480                return;
1481            }
1482        }
1483        render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs);
1484    } else if let Some(prim) = target.primitive_type()
1485        && let Some(&did) = cache.primitive_locations.get(&prim)
1486    {
1487        render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs);
1488    }
1489}
1490
1491fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
1492    let self_type_opt = match item.kind {
1493        clean::MethodItem(ref method, _) => method.decl.receiver_type(),
1494        clean::RequiredMethodItem(ref method) => method.decl.receiver_type(),
1495        _ => None,
1496    };
1497
1498    if let Some(self_ty) = self_type_opt {
1499        let (by_mut_ref, by_box, by_value) = match *self_ty {
1500            clean::Type::BorrowedRef { mutability, .. } => {
1501                (mutability == Mutability::Mut, false, false)
1502            }
1503            clean::Type::Path { ref path } => {
1504                (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
1505            }
1506            clean::Type::SelfTy => (false, false, true),
1507            _ => (false, false, false),
1508        };
1509
1510        (deref_mut_ || !by_mut_ref) && !by_box && !by_value
1511    } else {
1512        false
1513    }
1514}
1515
1516fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Option<impl fmt::Display> {
1517    if ty.is_unit() {
1518        // Very common fast path.
1519        return None;
1520    }
1521
1522    let did = ty.def_id(cx.cache())?;
1523
1524    // Box has pass-through impls for Read, Write, Iterator, and Future when the
1525    // boxed type implements one of those. We don't want to treat every Box return
1526    // as being notably an Iterator (etc), though, so we exempt it. Pin has the same
1527    // issue, with a pass-through impl for Future.
1528    if Some(did) == cx.tcx().lang_items().owned_box()
1529        || Some(did) == cx.tcx().lang_items().pin_type()
1530    {
1531        return None;
1532    }
1533
1534    let impls = cx.cache().impls.get(&did)?;
1535    let has_notable_trait = impls
1536        .iter()
1537        .map(Impl::inner_impl)
1538        .filter(|impl_| {
1539            impl_.polarity == ty::ImplPolarity::Positive
1540                // Two different types might have the same did,
1541                // without actually being the same.
1542                && ty.is_doc_subtype_of(&impl_.for_, cx.cache())
1543        })
1544        .filter_map(|impl_| impl_.trait_.as_ref())
1545        .filter_map(|trait_| cx.cache().traits.get(&trait_.def_id()))
1546        .any(|t| t.is_notable_trait(cx.tcx()));
1547
1548    has_notable_trait.then(|| {
1549        cx.types_with_notable_traits.borrow_mut().insert(ty.clone());
1550        fmt::from_fn(|f| {
1551            write!(
1552                f,
1553                " <a href=\"#\" class=\"tooltip\" data-notable-ty=\"{ty}\">ⓘ</a>",
1554                ty = Escape(&format!("{:#}", ty.print(cx))),
1555            )
1556        })
1557    })
1558}
1559
1560fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
1561    let mut out = String::new();
1562
1563    let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this");
1564
1565    let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this");
1566
1567    for i in impls {
1568        let impl_ = i.inner_impl();
1569        if impl_.polarity != ty::ImplPolarity::Positive {
1570            continue;
1571        }
1572
1573        if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
1574            // Two different types might have the same did,
1575            // without actually being the same.
1576            continue;
1577        }
1578        if let Some(trait_) = &impl_.trait_ {
1579            let trait_did = trait_.def_id();
1580
1581            if cx.cache().traits.get(&trait_did).is_some_and(|t| t.is_notable_trait(cx.tcx())) {
1582                if out.is_empty() {
1583                    write_str(
1584                        &mut out,
1585                        format_args!(
1586                            "<h3>Notable traits for <code>{}</code></h3>\
1587                            <pre><code>",
1588                            impl_.for_.print(cx)
1589                        ),
1590                    );
1591                }
1592
1593                write_str(
1594                    &mut out,
1595                    format_args!("<div class=\"where\">{}</div>", impl_.print(false, cx)),
1596                );
1597                for it in &impl_.items {
1598                    if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
1599                        let empty_set = FxIndexSet::default();
1600                        let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
1601                        write_str(
1602                            &mut out,
1603                            format_args!(
1604                                "<div class=\"where\">    {};</div>",
1605                                assoc_type(
1606                                    it,
1607                                    &tydef.generics,
1608                                    &[], // intentionally leaving out bounds
1609                                    Some(&tydef.type_),
1610                                    src_link,
1611                                    0,
1612                                    cx,
1613                                )
1614                            ),
1615                        );
1616                    }
1617                }
1618            }
1619        }
1620    }
1621    if out.is_empty() {
1622        out.push_str("</code></pre>");
1623    }
1624
1625    (format!("{:#}", ty.print(cx)), out)
1626}
1627
1628fn notable_traits_json<'a>(tys: impl Iterator<Item = &'a clean::Type>, cx: &Context<'_>) -> String {
1629    let mut mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect();
1630    mp.sort_by(|(name1, _html1), (name2, _html2)| name1.cmp(name2));
1631    struct NotableTraitsMap(Vec<(String, String)>);
1632    impl Serialize for NotableTraitsMap {
1633        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1634        where
1635            S: Serializer,
1636        {
1637            let mut map = serializer.serialize_map(Some(self.0.len()))?;
1638            for item in &self.0 {
1639                map.serialize_entry(&item.0, &item.1)?;
1640            }
1641            map.end()
1642        }
1643    }
1644    serde_json::to_string(&NotableTraitsMap(mp))
1645        .expect("serialize (string, string) -> json object cannot fail")
1646}
1647
1648#[derive(Clone, Copy, Debug)]
1649struct ImplRenderingParameters {
1650    show_def_docs: bool,
1651    show_default_items: bool,
1652    /// Whether or not to show methods.
1653    show_non_assoc_items: bool,
1654    toggle_open_by_default: bool,
1655}
1656
1657fn render_impl(
1658    cx: &Context<'_>,
1659    i: &Impl,
1660    parent: &clean::Item,
1661    link: AssocItemLink<'_>,
1662    render_mode: RenderMode,
1663    use_absolute: Option<bool>,
1664    aliases: &[String],
1665    rendering_params: ImplRenderingParameters,
1666) -> impl fmt::Display {
1667    fmt::from_fn(move |w| {
1668        let cache = &cx.shared.cache;
1669        let traits = &cache.traits;
1670        let trait_ = i.trait_did().map(|did| &traits[&did]);
1671        let mut close_tags = <Vec<&str>>::with_capacity(2);
1672
1673        // For trait implementations, the `interesting` output contains all methods that have doc
1674        // comments, and the `boring` output contains all methods that do not. The distinction is
1675        // used to allow hiding the boring methods.
1676        // `containing_item` is used for rendering stability info. If the parent is a trait impl,
1677        // `containing_item` will the grandparent, since trait impls can't have stability attached.
1678        fn doc_impl_item(
1679            boring: impl fmt::Write,
1680            interesting: impl fmt::Write,
1681            cx: &Context<'_>,
1682            item: &clean::Item,
1683            parent: &clean::Item,
1684            link: AssocItemLink<'_>,
1685            render_mode: RenderMode,
1686            is_default_item: bool,
1687            trait_: Option<&clean::Trait>,
1688            rendering_params: ImplRenderingParameters,
1689        ) -> fmt::Result {
1690            let item_type = item.type_();
1691            let name = item.name.as_ref().unwrap();
1692
1693            let render_method_item = rendering_params.show_non_assoc_items
1694                && match render_mode {
1695                    RenderMode::Normal => true,
1696                    RenderMode::ForDeref { mut_: deref_mut_ } => {
1697                        should_render_item(item, deref_mut_, cx.tcx())
1698                    }
1699                };
1700
1701            let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
1702
1703            let mut doc_buffer = String::new();
1704            let mut info_buffer = String::new();
1705            let mut short_documented = true;
1706
1707            if render_method_item {
1708                if !is_default_item {
1709                    if let Some(t) = trait_ {
1710                        // The trait item may have been stripped so we might not
1711                        // find any documentation or stability for it.
1712                        if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
1713                            // We need the stability of the item from the trait
1714                            // because impls can't have a stability.
1715                            if !item.doc_value().is_empty() {
1716                                document_item_info(cx, it, Some(parent))
1717                                    .render_into(&mut info_buffer)
1718                                    .unwrap();
1719                                write_str(
1720                                    &mut doc_buffer,
1721                                    format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
1722                                );
1723                                short_documented = false;
1724                            } else {
1725                                // In case the item isn't documented,
1726                                // provide short documentation from the trait.
1727                                write_str(
1728                                    &mut doc_buffer,
1729                                    format_args!(
1730                                        "{}",
1731                                        document_short(
1732                                            it,
1733                                            cx,
1734                                            link,
1735                                            parent,
1736                                            rendering_params.show_def_docs,
1737                                        )
1738                                    ),
1739                                );
1740                            }
1741                        }
1742                    } else {
1743                        document_item_info(cx, item, Some(parent))
1744                            .render_into(&mut info_buffer)
1745                            .unwrap();
1746                        if rendering_params.show_def_docs {
1747                            write_str(
1748                                &mut doc_buffer,
1749                                format_args!("{}", document_full(item, cx, HeadingOffset::H5)),
1750                            );
1751                            short_documented = false;
1752                        }
1753                    }
1754                } else {
1755                    write_str(
1756                        &mut doc_buffer,
1757                        format_args!(
1758                            "{}",
1759                            document_short(item, cx, link, parent, rendering_params.show_def_docs)
1760                        ),
1761                    );
1762                }
1763            }
1764            let mut w = if short_documented && trait_.is_some() {
1765                Either::Left(interesting)
1766            } else {
1767                Either::Right(boring)
1768            };
1769
1770            let toggled = !doc_buffer.is_empty();
1771            if toggled {
1772                let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
1773                write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>")?;
1774            }
1775            match &item.kind {
1776                clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
1777                    // Only render when the method is not static or we allow static methods
1778                    if render_method_item {
1779                        let id = cx.derive_id(format!("{item_type}.{name}"));
1780                        let source_id = trait_
1781                            .and_then(|trait_| {
1782                                trait_
1783                                    .items
1784                                    .iter()
1785                                    .find(|item| item.name.map(|n| n == *name).unwrap_or(false))
1786                            })
1787                            .map(|item| format!("{}.{name}", item.type_()));
1788                        write!(
1789                            w,
1790                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
1791                                {}",
1792                            render_rightside(cx, item, render_mode)
1793                        )?;
1794                        if trait_.is_some() {
1795                            // Anchors are only used on trait impls.
1796                            write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
1797                        }
1798                        write!(
1799                            w,
1800                            "<h4 class=\"code-header\">{}</h4></section>",
1801                            render_assoc_item(
1802                                item,
1803                                link.anchor(source_id.as_ref().unwrap_or(&id)),
1804                                ItemType::Impl,
1805                                cx,
1806                                render_mode,
1807                            ),
1808                        )?;
1809                    }
1810                }
1811                clean::RequiredAssocConstItem(generics, ty) => {
1812                    let source_id = format!("{item_type}.{name}");
1813                    let id = cx.derive_id(&source_id);
1814                    write!(
1815                        w,
1816                        "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
1817                            {}",
1818                        render_rightside(cx, item, render_mode)
1819                    )?;
1820                    if trait_.is_some() {
1821                        // Anchors are only used on trait impls.
1822                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
1823                    }
1824                    write!(
1825                        w,
1826                        "<h4 class=\"code-header\">{}</h4></section>",
1827                        assoc_const(
1828                            item,
1829                            generics,
1830                            ty,
1831                            AssocConstValue::None,
1832                            link.anchor(if trait_.is_some() { &source_id } else { &id }),
1833                            0,
1834                            cx,
1835                        ),
1836                    )?;
1837                }
1838                clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => {
1839                    let source_id = format!("{item_type}.{name}");
1840                    let id = cx.derive_id(&source_id);
1841                    write!(
1842                        w,
1843                        "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
1844                            {}",
1845                        render_rightside(cx, item, render_mode),
1846                    )?;
1847                    if trait_.is_some() {
1848                        // Anchors are only used on trait impls.
1849                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
1850                    }
1851                    write!(
1852                        w,
1853                        "<h4 class=\"code-header\">{}</h4></section>",
1854                        assoc_const(
1855                            item,
1856                            &ci.generics,
1857                            &ci.type_,
1858                            match item.kind {
1859                                clean::ProvidedAssocConstItem(_) =>
1860                                    AssocConstValue::TraitDefault(&ci.kind),
1861                                clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind),
1862                                _ => unreachable!(),
1863                            },
1864                            link.anchor(if trait_.is_some() { &source_id } else { &id }),
1865                            0,
1866                            cx,
1867                        ),
1868                    )?;
1869                }
1870                clean::RequiredAssocTypeItem(generics, bounds) => {
1871                    let source_id = format!("{item_type}.{name}");
1872                    let id = cx.derive_id(&source_id);
1873                    write!(
1874                        w,
1875                        "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
1876                            {}",
1877                        render_rightside(cx, item, render_mode),
1878                    )?;
1879                    if trait_.is_some() {
1880                        // Anchors are only used on trait impls.
1881                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
1882                    }
1883                    write!(
1884                        w,
1885                        "<h4 class=\"code-header\">{}</h4></section>",
1886                        assoc_type(
1887                            item,
1888                            generics,
1889                            bounds,
1890                            None,
1891                            link.anchor(if trait_.is_some() { &source_id } else { &id }),
1892                            0,
1893                            cx,
1894                        ),
1895                    )?;
1896                }
1897                clean::AssocTypeItem(tydef, _bounds) => {
1898                    let source_id = format!("{item_type}.{name}");
1899                    let id = cx.derive_id(&source_id);
1900                    write!(
1901                        w,
1902                        "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
1903                            {}",
1904                        render_rightside(cx, item, render_mode),
1905                    )?;
1906                    if trait_.is_some() {
1907                        // Anchors are only used on trait impls.
1908                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
1909                    }
1910                    write!(
1911                        w,
1912                        "<h4 class=\"code-header\">{}</h4></section>",
1913                        assoc_type(
1914                            item,
1915                            &tydef.generics,
1916                            &[], // intentionally leaving out bounds
1917                            Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
1918                            link.anchor(if trait_.is_some() { &source_id } else { &id }),
1919                            0,
1920                            cx,
1921                        ),
1922                    )?;
1923                }
1924                clean::StrippedItem(..) => return Ok(()),
1925                _ => panic!("can't make docs for trait item with name {:?}", item.name),
1926            }
1927
1928            w.write_str(&info_buffer)?;
1929            if toggled {
1930                write!(w, "</summary>{doc_buffer}</details>")?;
1931            }
1932            Ok(())
1933        }
1934
1935        let mut impl_items = String::new();
1936        let mut default_impl_items = String::new();
1937        let impl_ = i.inner_impl();
1938
1939        // Impl items are grouped by kinds:
1940        //
1941        // 1. Constants
1942        // 2. Types
1943        // 3. Functions
1944        //
1945        // This order is because you can have associated constants used in associated types (like array
1946        // length), and both in associated functions. So with this order, when reading from top to
1947        // bottom, you should see items definitions before they're actually used most of the time.
1948        let mut assoc_types = Vec::new();
1949        let mut methods = Vec::new();
1950
1951        if !impl_.is_negative_trait_impl() {
1952            for trait_item in &impl_.items {
1953                match trait_item.kind {
1954                    clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
1955                        methods.push(trait_item)
1956                    }
1957                    clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
1958                        assoc_types.push(trait_item)
1959                    }
1960                    clean::RequiredAssocConstItem(..)
1961                    | clean::ProvidedAssocConstItem(_)
1962                    | clean::ImplAssocConstItem(_) => {
1963                        // We render it directly since they're supposed to come first.
1964                        doc_impl_item(
1965                            &mut default_impl_items,
1966                            &mut impl_items,
1967                            cx,
1968                            trait_item,
1969                            if trait_.is_some() { &i.impl_item } else { parent },
1970                            link,
1971                            render_mode,
1972                            false,
1973                            trait_,
1974                            rendering_params,
1975                        )?;
1976                    }
1977                    _ => {}
1978                }
1979            }
1980
1981            for assoc_type in assoc_types {
1982                doc_impl_item(
1983                    &mut default_impl_items,
1984                    &mut impl_items,
1985                    cx,
1986                    assoc_type,
1987                    if trait_.is_some() { &i.impl_item } else { parent },
1988                    link,
1989                    render_mode,
1990                    false,
1991                    trait_,
1992                    rendering_params,
1993                )?;
1994            }
1995            for method in methods {
1996                doc_impl_item(
1997                    &mut default_impl_items,
1998                    &mut impl_items,
1999                    cx,
2000                    method,
2001                    if trait_.is_some() { &i.impl_item } else { parent },
2002                    link,
2003                    render_mode,
2004                    false,
2005                    trait_,
2006                    rendering_params,
2007                )?;
2008            }
2009        }
2010
2011        fn render_default_items(
2012            mut boring: impl fmt::Write,
2013            mut interesting: impl fmt::Write,
2014            cx: &Context<'_>,
2015            t: &clean::Trait,
2016            i: &clean::Impl,
2017            parent: &clean::Item,
2018            render_mode: RenderMode,
2019            rendering_params: ImplRenderingParameters,
2020        ) -> fmt::Result {
2021            for trait_item in &t.items {
2022                // Skip over any default trait items that are impossible to reference
2023                // (e.g. if it has a `Self: Sized` bound on an unsized type).
2024                if let Some(impl_def_id) = parent.item_id.as_def_id()
2025                    && let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
2026                    && cx.tcx().is_impossible_associated_item((impl_def_id, trait_item_def_id))
2027                {
2028                    continue;
2029                }
2030
2031                let n = trait_item.name;
2032                if i.items.iter().any(|m| m.name == n) {
2033                    continue;
2034                }
2035                let did = i.trait_.as_ref().unwrap().def_id();
2036                let provided_methods = i.provided_trait_methods(cx.tcx());
2037                let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
2038
2039                doc_impl_item(
2040                    &mut boring,
2041                    &mut interesting,
2042                    cx,
2043                    trait_item,
2044                    parent,
2045                    assoc_link,
2046                    render_mode,
2047                    true,
2048                    Some(t),
2049                    rendering_params,
2050                )?;
2051            }
2052            Ok(())
2053        }
2054
2055        // If we've implemented a trait, then also emit documentation for all
2056        // default items which weren't overridden in the implementation block.
2057        // We don't emit documentation for default items if they appear in the
2058        // Implementations on Foreign Types or Implementors sections.
2059        if rendering_params.show_default_items
2060            && let Some(t) = trait_
2061            && !impl_.is_negative_trait_impl()
2062        {
2063            render_default_items(
2064                &mut default_impl_items,
2065                &mut impl_items,
2066                cx,
2067                t,
2068                impl_,
2069                &i.impl_item,
2070                render_mode,
2071                rendering_params,
2072            )?;
2073        }
2074        if render_mode == RenderMode::Normal {
2075            let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
2076            if toggled {
2077                close_tags.push("</details>");
2078                write!(
2079                    w,
2080                    "<details class=\"toggle implementors-toggle\"{}>\
2081                        <summary>",
2082                    if rendering_params.toggle_open_by_default { " open" } else { "" }
2083                )?;
2084            }
2085
2086            let (before_dox, after_dox) = i
2087                .impl_item
2088                .opt_doc_value()
2089                .map(|dox| {
2090                    Markdown {
2091                        content: &dox,
2092                        links: &i.impl_item.links(cx),
2093                        ids: &mut cx.id_map.borrow_mut(),
2094                        error_codes: cx.shared.codes,
2095                        edition: cx.shared.edition(),
2096                        playground: &cx.shared.playground,
2097                        heading_offset: HeadingOffset::H4,
2098                    }
2099                    .split_summary_and_content()
2100                })
2101                .unwrap_or((None, None));
2102
2103            write!(
2104                w,
2105                "{}",
2106                render_impl_summary(
2107                    cx,
2108                    i,
2109                    parent,
2110                    rendering_params.show_def_docs,
2111                    use_absolute,
2112                    aliases,
2113                    before_dox.as_deref(),
2114                    trait_.is_none() && impl_.items.is_empty(),
2115                )
2116            )?;
2117            if toggled {
2118                w.write_str("</summary>")?;
2119            }
2120
2121            if before_dox.is_some()
2122                && let Some(after_dox) = after_dox
2123            {
2124                write!(w, "<div class=\"docblock\">{after_dox}</div>")?;
2125            }
2126
2127            if !default_impl_items.is_empty() || !impl_items.is_empty() {
2128                w.write_str("<div class=\"impl-items\">")?;
2129                close_tags.push("</div>");
2130            }
2131        }
2132        if !default_impl_items.is_empty() || !impl_items.is_empty() {
2133            w.write_str(&default_impl_items)?;
2134            w.write_str(&impl_items)?;
2135        }
2136        for tag in close_tags.into_iter().rev() {
2137            w.write_str(tag)?;
2138        }
2139        Ok(())
2140    })
2141}
2142
2143// Render the items that appear on the right side of methods, impls, and
2144// associated types. For example "1.0.0 (const: 1.39.0) · source".
2145fn render_rightside(
2146    cx: &Context<'_>,
2147    item: &clean::Item,
2148    render_mode: RenderMode,
2149) -> impl fmt::Display {
2150    let tcx = cx.tcx();
2151
2152    fmt::from_fn(move |w| {
2153        // FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
2154        // this condition.
2155        let const_stability = match render_mode {
2156            RenderMode::Normal => item.const_stability(tcx),
2157            RenderMode::ForDeref { .. } => None,
2158        };
2159        let src_href = cx.src_href(item);
2160        let stability = render_stability_since_raw_with_extra(
2161            item.stable_since(tcx),
2162            const_stability,
2163            if src_href.is_some() { "" } else { " rightside" },
2164        );
2165
2166        match (stability, src_href) {
2167            (Some(stability), Some(link)) => {
2168                write!(
2169                    w,
2170                    "<span class=\"rightside\">{stability} · <a class=\"src\" href=\"{link}\">Source</a></span>",
2171                )
2172            }
2173            (Some(stability), None) => {
2174                write!(w, "{stability}")
2175            }
2176            (None, Some(link)) => {
2177                write!(w, "<a class=\"src rightside\" href=\"{link}\">Source</a>")
2178            }
2179            (None, None) => Ok(()),
2180        }
2181    })
2182}
2183
2184fn render_impl_summary(
2185    cx: &Context<'_>,
2186    i: &Impl,
2187    parent: &clean::Item,
2188    show_def_docs: bool,
2189    use_absolute: Option<bool>,
2190    // This argument is used to reference same type with different paths to avoid duplication
2191    // in documentation pages for trait with automatic implementations like "Send" and "Sync".
2192    aliases: &[String],
2193    doc: Option<&str>,
2194    impl_is_empty: bool,
2195) -> impl fmt::Display {
2196    fmt::from_fn(move |w| {
2197        let inner_impl = i.inner_impl();
2198        let id = cx.derive_id(get_id_for_impl(cx.tcx(), i.impl_item.item_id));
2199        let aliases = (!aliases.is_empty())
2200            .then_some(fmt::from_fn(|f| {
2201                write!(f, " data-aliases=\"{}\"", fmt::from_fn(|f| aliases.iter().joined(",", f)))
2202            }))
2203            .maybe_display();
2204        write!(
2205            w,
2206            "<section id=\"{id}\" class=\"impl\"{aliases}>\
2207                {}\
2208                <a href=\"#{id}\" class=\"anchor\">§</a>\
2209                <h3 class=\"code-header\">",
2210            render_rightside(cx, &i.impl_item, RenderMode::Normal)
2211        )?;
2212
2213        if let Some(use_absolute) = use_absolute {
2214            write!(w, "{}", inner_impl.print(use_absolute, cx))?;
2215            if show_def_docs {
2216                for it in &inner_impl.items {
2217                    if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
2218                        write!(
2219                            w,
2220                            "<div class=\"where\">  {};</div>",
2221                            assoc_type(
2222                                it,
2223                                &tydef.generics,
2224                                &[], // intentionally leaving out bounds
2225                                Some(&tydef.type_),
2226                                AssocItemLink::Anchor(None),
2227                                0,
2228                                cx,
2229                            )
2230                        )?;
2231                    }
2232                }
2233            }
2234        } else {
2235            write!(w, "{}", inner_impl.print(false, cx))?;
2236        }
2237        w.write_str("</h3>")?;
2238
2239        let is_trait = inner_impl.trait_.is_some();
2240        if is_trait && let Some(portability) = portability(&i.impl_item, Some(parent)) {
2241            write!(
2242                w,
2243                "<span class=\"item-info\">\
2244                    <div class=\"stab portability\">{portability}</div>\
2245                </span>",
2246            )?;
2247        }
2248
2249        if let Some(doc) = doc {
2250            if impl_is_empty {
2251                w.write_str(
2252                    "<div class=\"item-info\">\
2253                         <div class=\"stab empty-impl\">This impl block contains no items.</div>\
2254                     </div>",
2255                )?;
2256            }
2257            write!(w, "<div class=\"docblock\">{doc}</div>")?;
2258        }
2259
2260        w.write_str("</section>")
2261    })
2262}
2263
2264pub(crate) fn small_url_encode(s: String) -> String {
2265    // These characters don't need to be escaped in a URI.
2266    // See https://url.spec.whatwg.org/#query-percent-encode-set
2267    // and https://url.spec.whatwg.org/#urlencoded-parsing
2268    // and https://url.spec.whatwg.org/#url-code-points
2269    fn dont_escape(c: u8) -> bool {
2270        c.is_ascii_alphanumeric()
2271            || c == b'-'
2272            || c == b'_'
2273            || c == b'.'
2274            || c == b','
2275            || c == b'~'
2276            || c == b'!'
2277            || c == b'\''
2278            || c == b'('
2279            || c == b')'
2280            || c == b'*'
2281            || c == b'/'
2282            || c == b';'
2283            || c == b':'
2284            || c == b'?'
2285            // As described in urlencoded-parsing, the
2286            // first `=` is the one that separates key from
2287            // value. Following `=`s are part of the value.
2288            || c == b'='
2289    }
2290    let mut st = String::new();
2291    let mut last_match = 0;
2292    for (idx, b) in s.bytes().enumerate() {
2293        if dont_escape(b) {
2294            continue;
2295        }
2296
2297        if last_match != idx {
2298            // Invariant: `idx` must be the first byte in a character at this point.
2299            st += &s[last_match..idx];
2300        }
2301        if b == b' ' {
2302            // URL queries are decoded with + replaced with SP.
2303            // While the same is not true for hashes, rustdoc only needs to be
2304            // consistent with itself when encoding them.
2305            st += "+";
2306        } else {
2307            write!(st, "%{b:02X}").unwrap();
2308        }
2309        // Invariant: if the current byte is not at the start of a multi-byte character,
2310        // we need to get down here so that when the next turn of the loop comes around,
2311        // last_match winds up equalling idx.
2312        //
2313        // In other words, dont_escape must always return `false` in multi-byte character.
2314        last_match = idx + 1;
2315    }
2316
2317    if last_match != 0 {
2318        st += &s[last_match..];
2319        st
2320    } else {
2321        s
2322    }
2323}
2324
2325fn get_id_for_impl(tcx: TyCtxt<'_>, impl_id: ItemId) -> String {
2326    use rustc_middle::ty::print::with_forced_trimmed_paths;
2327    let (type_, trait_) = match impl_id {
2328        ItemId::Auto { trait_, for_ } => {
2329            let ty = tcx.type_of(for_).skip_binder();
2330            (ty, Some(ty::TraitRef::new(tcx, trait_, [ty])))
2331        }
2332        ItemId::Blanket { impl_id, .. } | ItemId::DefId(impl_id) => {
2333            match tcx.impl_subject(impl_id).skip_binder() {
2334                ty::ImplSubject::Trait(trait_ref) => {
2335                    (trait_ref.args[0].expect_ty(), Some(trait_ref))
2336                }
2337                ty::ImplSubject::Inherent(ty) => (ty, None),
2338            }
2339        }
2340    };
2341    with_forced_trimmed_paths!(small_url_encode(if let Some(trait_) = trait_ {
2342        format!("impl-{trait_}-for-{type_}", trait_ = trait_.print_only_trait_path())
2343    } else {
2344        format!("impl-{type_}")
2345    }))
2346}
2347
2348fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
2349    match item.kind {
2350        clean::ItemKind::ImplItem(ref i) if i.trait_.is_some() => {
2351            // Alternative format produces no URLs,
2352            // so this parameter does nothing.
2353            Some((format!("{:#}", i.for_.print(cx)), get_id_for_impl(cx.tcx(), item.item_id)))
2354        }
2355        _ => None,
2356    }
2357}
2358
2359/// Returns the list of implementations for the primitive reference type, filtering out any
2360/// implementations that are on concrete or partially generic types, only keeping implementations
2361/// of the form `impl<T> Trait for &T`.
2362pub(crate) fn get_filtered_impls_for_reference<'a>(
2363    shared: &'a SharedContext<'_>,
2364    it: &clean::Item,
2365) -> (Vec<&'a Impl>, Vec<&'a Impl>, Vec<&'a Impl>) {
2366    let def_id = it.item_id.expect_def_id();
2367    // If the reference primitive is somehow not defined, exit early.
2368    let Some(v) = shared.cache.impls.get(&def_id) else {
2369        return (Vec::new(), Vec::new(), Vec::new());
2370    };
2371    // Since there is no "direct implementation" on the reference primitive type, we filter out
2372    // every implementation which isn't a trait implementation.
2373    let traits = v.iter().filter(|i| i.inner_impl().trait_.is_some());
2374    let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
2375        traits.partition(|t| t.inner_impl().kind.is_auto());
2376
2377    let (blanket_impl, concrete): (Vec<&Impl>, _) =
2378        concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
2379    // Now we keep only references over full generic types.
2380    let concrete: Vec<_> = concrete
2381        .into_iter()
2382        .filter(|t| match t.inner_impl().for_ {
2383            clean::Type::BorrowedRef { ref type_, .. } => type_.is_full_generic(),
2384            _ => false,
2385        })
2386        .collect();
2387
2388    (concrete, synthetic, blanket_impl)
2389}
2390
2391#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2392pub(crate) enum ItemSection {
2393    Reexports,
2394    PrimitiveTypes,
2395    Modules,
2396    Macros,
2397    Structs,
2398    Enums,
2399    Constants,
2400    Statics,
2401    Traits,
2402    Functions,
2403    TypeAliases,
2404    Unions,
2405    Implementations,
2406    TypeMethods,
2407    Methods,
2408    StructFields,
2409    Variants,
2410    AssociatedTypes,
2411    AssociatedConstants,
2412    ForeignTypes,
2413    Keywords,
2414    AttributeMacros,
2415    DeriveMacros,
2416    TraitAliases,
2417}
2418
2419impl ItemSection {
2420    const ALL: &'static [Self] = {
2421        use ItemSection::*;
2422        // NOTE: The order here affects the order in the UI.
2423        // Keep this synchronized with addSidebarItems in main.js
2424        &[
2425            Reexports,
2426            PrimitiveTypes,
2427            Modules,
2428            Macros,
2429            Structs,
2430            Enums,
2431            Constants,
2432            Statics,
2433            Traits,
2434            Functions,
2435            TypeAliases,
2436            Unions,
2437            Implementations,
2438            TypeMethods,
2439            Methods,
2440            StructFields,
2441            Variants,
2442            AssociatedTypes,
2443            AssociatedConstants,
2444            ForeignTypes,
2445            Keywords,
2446            AttributeMacros,
2447            DeriveMacros,
2448            TraitAliases,
2449        ]
2450    };
2451
2452    fn id(self) -> &'static str {
2453        match self {
2454            Self::Reexports => "reexports",
2455            Self::Modules => "modules",
2456            Self::Structs => "structs",
2457            Self::Unions => "unions",
2458            Self::Enums => "enums",
2459            Self::Functions => "functions",
2460            Self::TypeAliases => "types",
2461            Self::Statics => "statics",
2462            Self::Constants => "constants",
2463            Self::Traits => "traits",
2464            Self::Implementations => "impls",
2465            Self::TypeMethods => "tymethods",
2466            Self::Methods => "methods",
2467            Self::StructFields => "fields",
2468            Self::Variants => "variants",
2469            Self::Macros => "macros",
2470            Self::PrimitiveTypes => "primitives",
2471            Self::AssociatedTypes => "associated-types",
2472            Self::AssociatedConstants => "associated-consts",
2473            Self::ForeignTypes => "foreign-types",
2474            Self::Keywords => "keywords",
2475            Self::AttributeMacros => "attributes",
2476            Self::DeriveMacros => "derives",
2477            Self::TraitAliases => "trait-aliases",
2478        }
2479    }
2480
2481    fn name(self) -> &'static str {
2482        match self {
2483            Self::Reexports => "Re-exports",
2484            Self::Modules => "Modules",
2485            Self::Structs => "Structs",
2486            Self::Unions => "Unions",
2487            Self::Enums => "Enums",
2488            Self::Functions => "Functions",
2489            Self::TypeAliases => "Type Aliases",
2490            Self::Statics => "Statics",
2491            Self::Constants => "Constants",
2492            Self::Traits => "Traits",
2493            Self::Implementations => "Implementations",
2494            Self::TypeMethods => "Type Methods",
2495            Self::Methods => "Methods",
2496            Self::StructFields => "Struct Fields",
2497            Self::Variants => "Variants",
2498            Self::Macros => "Macros",
2499            Self::PrimitiveTypes => "Primitive Types",
2500            Self::AssociatedTypes => "Associated Types",
2501            Self::AssociatedConstants => "Associated Constants",
2502            Self::ForeignTypes => "Foreign Types",
2503            Self::Keywords => "Keywords",
2504            Self::AttributeMacros => "Attribute Macros",
2505            Self::DeriveMacros => "Derive Macros",
2506            Self::TraitAliases => "Trait Aliases",
2507        }
2508    }
2509}
2510
2511fn item_ty_to_section(ty: ItemType) -> ItemSection {
2512    match ty {
2513        ItemType::ExternCrate | ItemType::Import => ItemSection::Reexports,
2514        ItemType::Module => ItemSection::Modules,
2515        ItemType::Struct => ItemSection::Structs,
2516        ItemType::Union => ItemSection::Unions,
2517        ItemType::Enum => ItemSection::Enums,
2518        ItemType::Function => ItemSection::Functions,
2519        ItemType::TypeAlias => ItemSection::TypeAliases,
2520        ItemType::Static => ItemSection::Statics,
2521        ItemType::Constant => ItemSection::Constants,
2522        ItemType::Trait => ItemSection::Traits,
2523        ItemType::Impl => ItemSection::Implementations,
2524        ItemType::TyMethod => ItemSection::TypeMethods,
2525        ItemType::Method => ItemSection::Methods,
2526        ItemType::StructField => ItemSection::StructFields,
2527        ItemType::Variant => ItemSection::Variants,
2528        ItemType::Macro => ItemSection::Macros,
2529        ItemType::Primitive => ItemSection::PrimitiveTypes,
2530        ItemType::AssocType => ItemSection::AssociatedTypes,
2531        ItemType::AssocConst => ItemSection::AssociatedConstants,
2532        ItemType::ForeignType => ItemSection::ForeignTypes,
2533        ItemType::Keyword => ItemSection::Keywords,
2534        ItemType::ProcAttribute => ItemSection::AttributeMacros,
2535        ItemType::ProcDerive => ItemSection::DeriveMacros,
2536        ItemType::TraitAlias => ItemSection::TraitAliases,
2537    }
2538}
2539
2540/// Returns a list of all paths used in the type.
2541/// This is used to help deduplicate imported impls
2542/// for reexported types. If any of the contained
2543/// types are re-exported, we don't use the corresponding
2544/// entry from the js file, as inlining will have already
2545/// picked up the impl
2546fn collect_paths_for_type(first_ty: &clean::Type, cache: &Cache) -> Vec<String> {
2547    let mut out = Vec::new();
2548    let mut visited = FxHashSet::default();
2549    let mut work = VecDeque::new();
2550
2551    let mut process_path = |did: DefId| {
2552        let get_extern = || cache.external_paths.get(&did).map(|s| &s.0);
2553        let fqp = cache.exact_paths.get(&did).or_else(get_extern);
2554
2555        if let Some(path) = fqp {
2556            out.push(join_path_syms(path));
2557        }
2558    };
2559
2560    work.push_back(first_ty);
2561
2562    while let Some(ty) = work.pop_front() {
2563        if !visited.insert(ty) {
2564            continue;
2565        }
2566
2567        match ty {
2568            clean::Type::Path { path } => process_path(path.def_id()),
2569            clean::Type::Tuple(tys) => {
2570                work.extend(tys.iter());
2571            }
2572            clean::Type::Slice(ty) => {
2573                work.push_back(ty);
2574            }
2575            clean::Type::Array(ty, _) => {
2576                work.push_back(ty);
2577            }
2578            clean::Type::RawPointer(_, ty) => {
2579                work.push_back(ty);
2580            }
2581            clean::Type::BorrowedRef { type_, .. } => {
2582                work.push_back(type_);
2583            }
2584            clean::Type::QPath(box clean::QPathData { self_type, trait_, .. }) => {
2585                work.push_back(self_type);
2586                if let Some(trait_) = trait_ {
2587                    process_path(trait_.def_id());
2588                }
2589            }
2590            _ => {}
2591        }
2592    }
2593    out
2594}
2595
2596const MAX_FULL_EXAMPLES: usize = 5;
2597const NUM_VISIBLE_LINES: usize = 10;
2598
2599/// Generates the HTML for example call locations generated via the --scrape-examples flag.
2600fn render_call_locations<W: fmt::Write>(
2601    mut w: W,
2602    cx: &Context<'_>,
2603    item: &clean::Item,
2604) -> fmt::Result {
2605    let tcx = cx.tcx();
2606    let def_id = item.item_id.expect_def_id();
2607    let key = tcx.def_path_hash(def_id);
2608    let Some(call_locations) = cx.shared.call_locations.get(&key) else { return Ok(()) };
2609
2610    // Generate a unique ID so users can link to this section for a given method
2611    let id = cx.derive_id("scraped-examples");
2612    write!(
2613        &mut w,
2614        "<div class=\"docblock scraped-example-list\">\
2615          <span></span>\
2616          <h5 id=\"{id}\">\
2617             <a href=\"#{id}\">Examples found in repository</a>\
2618             <a class=\"scrape-help\" href=\"{root_path}scrape-examples-help.html\">?</a>\
2619          </h5>",
2620        root_path = cx.root_path(),
2621        id = id
2622    )?;
2623
2624    // Create a URL to a particular location in a reverse-dependency's source file
2625    let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) {
2626        let (line_lo, line_hi) = loc.call_expr.line_span;
2627        let (anchor, title) = if line_lo == line_hi {
2628            ((line_lo + 1).to_string(), format!("line {}", line_lo + 1))
2629        } else {
2630            (
2631                format!("{}-{}", line_lo + 1, line_hi + 1),
2632                format!("lines {}-{}", line_lo + 1, line_hi + 1),
2633            )
2634        };
2635        let url = format!("{}{}#{anchor}", cx.root_path(), call_data.url);
2636        (url, title)
2637    };
2638
2639    // Generate the HTML for a single example, being the title and code block
2640    let write_example = |w: &mut W, (path, call_data): (&PathBuf, &CallData)| -> bool {
2641        let contents = match fs::read_to_string(path) {
2642            Ok(contents) => contents,
2643            Err(err) => {
2644                let span = item.span(tcx).map_or(DUMMY_SP, |span| span.inner());
2645                tcx.dcx().span_err(span, format!("failed to read file {}: {err}", path.display()));
2646                return false;
2647            }
2648        };
2649
2650        // To reduce file sizes, we only want to embed the source code needed to understand the example, not
2651        // the entire file. So we find the smallest byte range that covers all items enclosing examples.
2652        assert!(!call_data.locations.is_empty());
2653        let min_loc =
2654            call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
2655        let byte_min = min_loc.enclosing_item.byte_span.0;
2656        let line_min = min_loc.enclosing_item.line_span.0;
2657        let max_loc =
2658            call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap();
2659        let byte_max = max_loc.enclosing_item.byte_span.1;
2660        let line_max = max_loc.enclosing_item.line_span.1;
2661
2662        // The output code is limited to that byte range.
2663        let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
2664
2665        // The call locations need to be updated to reflect that the size of the program has changed.
2666        // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
2667        let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
2668            .locations
2669            .iter()
2670            .map(|loc| {
2671                let (byte_lo, byte_hi) = loc.call_ident.byte_span;
2672                let (line_lo, line_hi) = loc.call_expr.line_span;
2673                let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
2674
2675                let line_range = (line_lo - line_min, line_hi - line_min);
2676                let (line_url, line_title) = link_to_loc(call_data, loc);
2677
2678                (byte_range, (line_range, line_url, line_title))
2679            })
2680            .unzip();
2681
2682        let (_, init_url, init_title) = &line_ranges[0];
2683        let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
2684        let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
2685
2686        // Look for the example file in the source map if it exists, otherwise return a dummy span
2687        let file_span = (|| {
2688            let source_map = tcx.sess.source_map();
2689            let crate_src = tcx.sess.local_crate_source_file()?.into_local_path()?;
2690            let abs_crate_src = crate_src.canonicalize().ok()?;
2691            let crate_root = abs_crate_src.parent()?.parent()?;
2692            let rel_path = path.strip_prefix(crate_root).ok()?;
2693            let files = source_map.files();
2694            let file = files.iter().find(|file| match &file.name {
2695                FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path,
2696                _ => false,
2697            })?;
2698            Some(rustc_span::Span::with_root_ctxt(
2699                file.start_pos + BytePos(byte_min),
2700                file.start_pos + BytePos(byte_max),
2701            ))
2702        })()
2703        .unwrap_or(DUMMY_SP);
2704
2705        let mut decoration_info = FxIndexMap::default();
2706        decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
2707        decoration_info.insert("highlight", byte_ranges);
2708
2709        sources::print_src(
2710            w,
2711            contents_subset,
2712            file_span,
2713            cx,
2714            &cx.root_path(),
2715            &highlight::DecorationInfo(decoration_info),
2716            &sources::SourceContext::Embedded(sources::ScrapedInfo {
2717                needs_expansion,
2718                offset: line_min,
2719                name: &call_data.display_name,
2720                url: init_url,
2721                title: init_title,
2722                locations: locations_encoded,
2723            }),
2724        )
2725        .unwrap();
2726
2727        true
2728    };
2729
2730    // The call locations are output in sequence, so that sequence needs to be determined.
2731    // Ideally the most "relevant" examples would be shown first, but there's no general algorithm
2732    // for determining relevance. We instead proxy relevance with the following heuristics:
2733    //   1. Code written to be an example is better than code not written to be an example, e.g.
2734    //      a snippet from examples/foo.rs is better than src/lib.rs. We don't know the Cargo
2735    //      directory structure in Rustdoc, so we proxy this by prioritizing code that comes from
2736    //      a --crate-type bin.
2737    //   2. Smaller examples are better than large examples. So we prioritize snippets that have
2738    //      the smallest number of lines in their enclosing item.
2739    //   3. Finally we sort by the displayed file name, which is arbitrary but prevents the
2740    //      ordering of examples from randomly changing between Rustdoc invocations.
2741    let ordered_locations = {
2742        fn sort_criterion<'a>(
2743            (_, call_data): &(&PathBuf, &'a CallData),
2744        ) -> (bool, u32, &'a String) {
2745            // Use the first location because that's what the user will see initially
2746            let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
2747            (!call_data.is_bin, hi - lo, &call_data.display_name)
2748        }
2749
2750        let mut locs = call_locations.iter().collect::<Vec<_>>();
2751        locs.sort_by_key(sort_criterion);
2752        locs
2753    };
2754
2755    let mut it = ordered_locations.into_iter().peekable();
2756
2757    // An example may fail to write if its source can't be read for some reason, so this method
2758    // continues iterating until a write succeeds
2759    let write_and_skip_failure = |w: &mut W, it: &mut Peekable<_>| {
2760        for example in it.by_ref() {
2761            if write_example(&mut *w, example) {
2762                break;
2763            }
2764        }
2765    };
2766
2767    // Write just one example that's visible by default in the method's description.
2768    write_and_skip_failure(&mut w, &mut it);
2769
2770    // Then add the remaining examples in a hidden section.
2771    if it.peek().is_some() {
2772        write!(
2773            w,
2774            "<details class=\"toggle more-examples-toggle\">\
2775                  <summary class=\"hideme\">\
2776                     <span>More examples</span>\
2777                  </summary>\
2778                  <div class=\"hide-more\">Hide additional examples</div>\
2779                  <div class=\"more-scraped-examples\">\
2780                    <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>"
2781        )?;
2782
2783        // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
2784        // make the page arbitrarily huge!
2785        for _ in 0..MAX_FULL_EXAMPLES {
2786            write_and_skip_failure(&mut w, &mut it);
2787        }
2788
2789        // For the remaining examples, generate a <ul> containing links to the source files.
2790        if it.peek().is_some() {
2791            w.write_str(
2792                r#"<div class="example-links">Additional examples can be found in:<br><ul>"#,
2793            )?;
2794            it.try_for_each(|(_, call_data)| {
2795                let (url, _) = link_to_loc(call_data, &call_data.locations[0]);
2796                write!(
2797                    w,
2798                    r#"<li><a href="{url}">{name}</a></li>"#,
2799                    url = url,
2800                    name = call_data.display_name
2801                )
2802            })?;
2803            w.write_str("</ul></div>")?;
2804        }
2805
2806        w.write_str("</div></details>")?;
2807    }
2808
2809    w.write_str("</div>")
2810}