rustdoc/html/render/
mod.rs

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