Skip to main content

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