[go: up one dir, main page]

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