mod.rs - source (original) (raw)

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